실행 주변 패턴이 있는 상용구 코드를 제거해 보겠습니다.
이 기사에서는 먼저 전통적인 접근 방식을 사용하여 처음부터 스레드로부터 안전한 스택을 생성한 다음 주변 실행 설계 패턴으로 리팩터링할 것입니다.
스택은
last-in-first-out
(LIFO) 데이터 구조입니다. push
및 pop
두 가지 주요 방법이 있습니다. 만들어 봅시다 -package com.bazlur;
import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConcurrentStack<T> {
private final Lock lock = new ReentrantLock();
private T[] elements;
private int size = -1;
public ConcurrentStack() {
this(10);
}
public ConcurrentStack(int initialCapacity) {
this.elements = (T[]) new Object[initialCapacity];
}
public void push(T value) {
lock.lock();
try {
growIfNeeded();
elements[size] = value;
} finally {
lock.unlock();
}
}
public T pop() {
lock.lock();
try {
if (size == -1) {
throw new NoSuchElementException();
}
trimToSizeIfNeeded();
var element = elements[size];
elements[size] = null;
size--;
return element;
} finally {
lock.unlock();
}
}
private void growIfNeeded() {
if (++size == elements.length) {
grow();
}
}
private void grow() {
int newCapacity = elements.length * 2;
elements = Arrays.copyOf(elements, newCapacity);
}
private void trimToSizeIfNeeded() {
if (size < elements.length) {
elements = Arrays.copyOf(elements, size + 1);
}
}
}
이것은 가장 간단한 구현이며 많은 단점이 있습니다. 어쨌든 그것은 요점을 벗어났습니다.
푸시 앤 팝 방식을 살펴보십시오. 한 가지는 매우 일반적입니다. 자물쇠를 잠근 다음 잠금을 해제합니다. 이것은 상용구처럼 보이며 스택의 실제 비즈니스 로직과는 아무 관련이 없습니다.
이 상용구 코드를 다른 곳으로 옮기자-
package com.bazlur;
import java.util.concurrent.locks.Lock;
import java.util.function.Supplier;
public class LockHelper {
public static void withLock(Lock lock, Runnable runnable) {
lock.lock();
try {
runnable.run();
} finally {
lock.unlock();
}
}
public static <T> T withLock(Lock lock, Supplier<T> supplier) {
lock.lock();
try {
return supplier.get();
} finally {
lock.unlock();
}
}
}
첫 번째 방법은 잠금과 실행 가능 항목을 사용합니다. 잠금 및 조회를 수행하고 그 사이에 runnable의 run 메소드를 실행합니다. 다음 메서드도 잠금과 공급자를 사용합니다. 무언가를 반품해야 하는 경우에 대비하여 여기에서 공급업체를 사용했습니다.
ConcurrentStack에서 이러한 메서드를 사용해 봅시다.
package com.bazlur;
import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConcurrentStack2<T> {
private final Lock lock = new ReentrantLock();
private T[] elements;
private int size = -1;
public ConcurrentStack2() {
this(10);
}
public ConcurrentStack2(int initialCapacity) {
this.elements = (T[]) new Object[initialCapacity];
}
public void push(T value) {
LockHelper.withLock(lock, () -> {
growIfNeeded();
elements[size] = value;
});
}
public T pop() {
return LockHelper.withLock(lock, () -> {
if (size == -1) {
throw new NoSuchElementException();
}
trimToSizeIfNeeded();
var element = elements[size];
elements[size] = null;
size--;
return element;
});
}
private void growIfNeeded() {
if (++size == elements.length) {
grow();
}
}
private void grow() {
int newCapacity = elements.length * 2;
elements = Arrays.copyOf(elements, newCapacity);
}
private void trimToSizeIfNeeded() {
if (size < elements.length) {
elements = Arrays.copyOf(elements, size + 1);
}
}
}
이제 우리의 코드는 훨씬 깨끗해졌고 관련 코드를 잠그는 상용구가 없습니다.
이 클래스에 다른 메서드를 추가하려면 비슷한 패턴을 사용합니다. –
public T peek() {
return LockHelper.withLock(lock, () -> elements[size]);
}
우리는 눈앞에 존재하지 않는 것처럼 보이는 무언가에 대해 코드를 실행하고 노이즈를 제거하고 명확성을 가져옵니다. 이것이 바로 디자인 패턴 주변 실행이라고 하는 이유이며 유사한 상용구 코드를 많이 제거하는 데 도움이 됩니다.
오늘은!
건배!!
복사/붙여넣기: https://github.com/rokon12/100DaysOfJava/blob/main/src/main/java/com/bazlur/ConcurrentStack2.java
Reference
이 문제에 관하여(실행 주변 패턴이 있는 상용구 코드를 제거해 보겠습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/bazlur_rahman/let-s-remove-the-boilerplate-code-with-execute-around-pattern-5ebi텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)