이그제큐트 어라운드(Execute Around)라는 사자성어가 뭐죠?
제가 듣던 '이그제큐트 어라운드' 관용어(또는 이와 비슷한 말)는 무엇입니까?왜 사용하는지, 왜 사용하지 않을 수 있는 이유는 무엇입니까?
기본적으로는 자원 할당이나 청소 등 항상 필요한 작업을 수행하는 방법을 작성하여 발신자에게 "리소스로 하고 싶은 일"을 전달하도록 하는 패턴입니다.예를 들어 다음과 같습니다.
public interface InputStreamAction
{
void useStream(InputStream stream) throws IOException;
}
// Somewhere else
public void executeWithFile(String filename, InputStreamAction action)
throws IOException
{
InputStream stream = new FileInputStream(filename);
try {
action.useStream(stream);
} finally {
stream.close();
}
}
// Calling it
executeWithFile("filename.txt", new InputStreamAction()
{
public void useStream(InputStream stream) throws IOException
{
// Code to use the stream goes here
}
});
// Calling it with Java 8 Lambda Expression:
executeWithFile("filename.txt", s -> System.out.println(s.read()));
// Or with Java 8 Method reference:
executeWithFile("filename.txt", ClassName::methodName);
는, 오픈 코드는, 신청청, 청청청/청청청청, 청청청청청청 the에 의해서 됩니다.이쪽은 에 의해서 처리됩니다.executeWithFile
.
expressions 에서와 같이 8 lambda expressions를 구현할 수 , 에서 Java를 사용하는 에서 이 한 사례가 때문에 이 . 왜냐하면 폐쇄가 너무 시끄러웠기 때문입니다. Java 8 lambda 표현은 다른 많은 언어에서처럼 구현될 수 있습니다(예: C# lambda 표현 또는 Groovy). 자바 7을 사용합니다.try-with-resources
★★★★★★★★★★★★★★★★★」AutoClosable
트림입입니니다
"할당 및 정리"가 일반적인 예이지만 트랜잭션 처리, 로깅, 더 많은 권한을 가진 일부 코드 실행 등 다른 많은 예가 있습니다.기본적으로는 템플릿 방식 패턴과 비슷하지만 상속은 없습니다.
Execute Around 관용구는 다음과 같은 작업을 수행해야 할 때 사용됩니다.
//... chunk of init/preparation code ...
task A
//... chunk of cleanup/finishing code ...
//... chunk of identical init/preparation code ...
task B
//... chunk of identical cleanup/finishing code ...
//... chunk of identical init/preparation code ...
task C
//... chunk of identical cleanup/finishing code ...
//... and so on.
항상 실제 작업을 "주변"으로 실행하는 이 중복 코드를 모두 반복하지 않도록 자동으로 처리하는 클래스를 만듭니다.
//pseudo-code:
class DoTask()
{
do(task T)
{
// .. chunk of prep code
// execute task T
// .. chunk of cleanup code
}
};
DoTask.do(task A)
DoTask.do(task B)
DoTask.do(task C)
이 관용구는 복잡한 중복 코드를 모두 한 곳으로 이동시켜 메인 프로그램의 가독성을 향상시킵니다(유지관리 가능).
C# 의 예에 대해서는 이 투고를, C++ 의 예에 대해서는 이 기사를 참조해 주세요.
코드 샌드위치도 참조해 주세요.이 코드 샌드위치는 여러 프로그래밍 언어에 걸쳐 이 구조를 조사하여 흥미로운 연구 아이디어를 제공합니다.왜 그것을 사용하는지에 대한 구체적인 질문에 대해서는, 상기의 몇개의 구체적인 예를 제시합니다.
이러한 상황은 프로그램이 공유 리소스를 조작할 때마다 발생합니다.잠금, 소켓, 파일 또는 데이터베이스 연결을 위한 API에서는 이전에 획득한 리소스를 명시적으로 닫거나 해제하는 프로그램이 필요할 수 있습니다.가비지 컬렉션이 없는 언어에서 프로그래머는 메모리를 사용하기 전에 할당하고 사용 후에 메모리를 해방할 책임이 있습니다.일반적으로, 다양한 프로그래밍 태스크는 프로그램 변경을 요구하고, 그 변경의 컨텍스트에서 동작한 후 변경을 원래대로 되돌립니다.우리는 이러한 상황을 코드 샌드위치라고 부른다.
그리고 나중에:
코드 샌드위치는 많은 프로그래밍 상황에서 나타납니다.잠금, 파일 기술자 또는 소켓 연결과 같은 희소 리소스의 획득 및 릴리스와 관련된 몇 가지 일반적인 예가 있습니다.보다 일반적인 경우, 프로그램 상태의 일시적인 변경에는 코드 샌드위치가 필요할 수 있습니다.예를 들어 GUI 기반 프로그램은 일시적으로 사용자 입력을 무시하거나 OS 커널이 일시적으로 하드웨어 인터럽트를 비활성화할 수 있습니다.이러한 경우 이전 상태를 복원하지 못하면 심각한 버그가 발생합니다.
이 문서에서는 이 관용구를 사용하지 않는 이유에 대해 설명하지는 않지만 언어 수준의 도움 없이 관용구를 틀리기 쉬운 이유를 설명합니다.
결함 코드 샌드위치는 예외 및 관련 보이지 않는 제어 흐름에서 가장 자주 발생합니다.실제로 코드 샌드위치를 관리하기 위한 특별한 언어 기능은 예외를 지원하는 언어에서 주로 발생합니다.
그러나 코드 샌드위치 결함의 원인은 예외뿐만이 아닙니다.바디 코드가 변경될 때마다 A/S 코드를 우회하는 새로운 제어 경로가 발생할 수 있습니다.가장 심플한 경우, 유지보수는 다음 명령어를 추가하기만 하면 됩니다.
return
샌드위치 본체에 전달하여 새로운 결함을 발생시키고, 이로 인해 무음 오류가 발생할 수 있습니다.보디코드가 크고 전후가 크게 분리되어 있으면 이러한 실수는 시각적으로 발견하기 어려울 수 있습니다.
Execute Around 메서드는 임의의 코드를 메서드에 전달하는 방식입니다.메서드는 셋업 및/또는 해체 코드를 실행하고 그 사이에 코드를 실행할 수 있습니다.
자바는 제가 선택한 언어가 아닙니다.인수로 폐쇄(또는 람다 표현식)를 전달하는 것이 더 스타일리시합니다.비록 물체는 거의 폐쇄와 동일하지만.
Execute Around 메서드는 Inversion of Control(Dependency Injection)과 비슷하기 때문에 메서드를 호출할 때마다 애드혹으로 변경할 수 있습니다.
그러나 이는 제어 결합(이 경우 문자 그대로 인수에 의해 방법을 알려줌)의 예로 해석될 수도 있습니다.
여기 Java 태그가 있습니다.그래서 플랫폼 고유의 패턴이 아니더라도 Java를 예로 들겠습니다.
코드 실행 전과 실행 후에 항상 같은 보일러 플레이트를 사용하는 코드가 있을 수 있습니다.좋은 예로는 JDBC가 있습니다.실제 쿼리를 실행하여 결과 세트를 처리하기 전에 항상 연결을 잡아 스테이트먼트(또는 준비된 스테이트먼트)를 작성한 후 마지막에 항상 동일한 보일러 플레이트의 청소(스테이트먼트 및 연결 닫기)를 수행합니다.
execute-around의 아이디어는 보일러 플레이트 코드를 제외할 수 있는 것이 더 낫다는 것입니다.그렇게 하면 타이핑은 덜 되지만, 그 이유는 더 깊어집니다.이 원칙은 Don't-Repeat-Yourself(DRY) 원칙입니다.코드를 한 곳으로 분리하면 버그가 발생하거나 변경할 필요가 있거나 이해만 하면 모든 것이 한 곳에 있습니다.
이런 종류의 배제에 있어서 조금 곤란한 것은, 「전」과「후」의 양쪽 모두가 참조할 필요가 있는 레퍼런스가 있다는 것입니다.JDBC의 예에서는 Connection과 (Prepared)가 포함됩니다.진술.따라서 이를 처리하기 위해 타겟 코드를 보일러 플레이트 코드로 "랩"합니다.
Java에서 흔히 볼 수 있는 몇 가지 사례를 알고 있을 것입니다.하나는 서블릿 필터입니다.다른 하나는 조언에 관한 AOP입니다.세 번째는 봄의 다양한 xxxTemplate 클래스입니다.어느 경우든 대상 코드(JDBC 쿼리 및 결과 세트 처리 등)가 삽입되는 래퍼 오브젝트가 있습니다.래퍼 객체는 "before" 부분을 수행하고 대상 코드를 호출한 다음 "after" 부분을 수행합니다.
네 살배기에게 설명하듯이 설명하겠습니다.
예 1
산타가 마을로 오고 있어그의 요정들은 그의 뒤에서 그들이 원하는 모든 것을 코드화한다. 그리고 그들이 상황을 바꾸지 않는 한, 조금 반복된다.
- 포장지 가져오기
- 슈퍼 닌텐도를 구입하세요.
- 포장해 주세요.
또는 다음과 같습니다.
- 포장지 가져오기
- 바비인형을 사세요.
- 포장해 주세요.
...여러 가지 선물에 대해 몇 백만 번이고 구역질을 합니다.다른 것은 2단계뿐이라는 것을 주의하세요.2단계만 다를 경우 Santa는 왜 코드를 복제합니까? 즉, 1단계와 3단계를 100만 번 복제합니까?100만 선물은 그가 불필요하게 1단계와 3단계를 100만 번 반복하고 있다는 것을 의미한다.
이 문제를 해결하는 데 도움이 됩니다.코드 제거에 도움이 됩니다.스텝 1과 스텝3은 기본적으로 일정하기 때문에 스텝2만 변경할 수 있습니다.
예 #2
만약 여러분이 여전히 그것을 이해하지 못한다면, 여기 또 다른 예가 있습니다: 모래를 생각해 보세요: 겉에 있는 빵은 항상 같지만 안에 있는 것은 여러분이 선택하는 모래의 종류에 따라 달라집니다. (예를 들어 햄, 치즈, 잼, 땅콩 버터 등)빵은 항상 겉에 있기 때문에 만드는 모든 종류의 모래에 대해 10억 번 반복할 필요가 없습니다.
위의 설명을 읽으시면 이해하기 쉬울 겁니다.이 설명이 당신에게 도움이 되었기를 바랍니다.
이것은 전략 디자인 패턴을 생각나게 합니다.제가 가리킨 링크에는 패턴의 Java 코드가 포함되어 있습니다.
초기화 및 정리 코드를 만들고 전략을 전달함으로써 "Execute Around(실행 어라운드)"를 수행할 수 있습니다. 이 코드는 항상 초기화 및 정리 코드로 포장됩니다.
코드 반복을 줄이기 위해 사용되는 모든 기술과 마찬가지로 필요한 경우가 최소 2개(YAGNI 원칙이라고도 함)가 있을 때까지 사용하지 마십시오.코드 반복을 제거하면 유지보수가 줄어들 뿐만 아니라(코드 복사본 수가 적을수록 각 복사본에서 수정 수정 사항을 복사하는 데 소요되는 시간이 줄어듭니다), 유지보수도 증가합니다(총 코드 수 증가).따라서 이 트릭의 대가는 코드를 추가하는 것입니다.
이 기술은 단순히 초기화 및 청소에만 유용한 것이 아닙니다.또한 함수를 보다 쉽게 호출할 수 있도록 하고 싶은 경우에도 유용합니다(예를 들어 마법사에서 사용할 수 있으므로 "다음" 및 "이전" 단추에 대소문자가 필요하지 않고 다음/이전 페이지로 이동할 수 있습니다).
멋진 관용구를 원하신다면, 여기 있습니다.
//-- the target class
class Resource {
def open () { // sensitive operation }
def close () { // sensitive operation }
//-- target method
def doWork() { println "working";} }
//-- the execute around code
def static use (closure) {
def res = new Resource();
try {
res.open();
closure(res)
} finally {
res.close();
}
}
//-- using the code
Resource.use { res -> res.doWork(); }
언급URL : https://stackoverflow.com/questions/341971/what-is-the-execute-around-idiom
'programing' 카테고리의 다른 글
For Loop의 fork()에 대해 시각적으로 표시되는 동작 (0) | 2022.08.10 |
---|---|
Vue Uncaught TypeError: fn.bind가 함수가 아닙니다. (0) | 2022.08.10 |
다른 계산된 속성에서 getter를 호출하는 것은 테스트의 함수가 아닙니다. (0) | 2022.08.09 |
Java 8 lamdas, Function.identity() 또는 t->t (0) | 2022.08.09 |
GCC/G++ 컴파일러에서 pedantic을 사용하는 목적은 무엇입니까? (0) | 2022.08.09 |