diff --git "a/\355\226\211\353\217\231/7\354\243\274\354\260\250-\354\261\205\354\236\204 \354\227\260\354\207\204/summary/example-code.md" "b/\355\226\211\353\217\231/7\354\243\274\354\260\250-\354\261\205\354\236\204 \354\227\260\354\207\204/summary/example-code.md" new file mode 100644 index 0000000..c6c228b --- /dev/null +++ "b/\355\226\211\353\217\231/7\354\243\274\354\260\250-\354\261\205\354\236\204 \354\227\260\354\207\204/summary/example-code.md" @@ -0,0 +1,350 @@ +# 책임 연쇄 패턴 예제 + +먼저 개발자가 개발 업무를 처리하고 작업자를 저장하는 과정이 있다 해보자. 아래는 간단 예제 코드이다. + +```java +/** + * 업무처리자 저장 클래스 + */ +public class IdeaRequest { + private String developer; + + public void printWorker() { + System.out.println("==================="); + System.out.printf("개발 : %s\n", this.developer); + System.out.println("==================="); + } + //...Setter + //...Getter +} + +/** + * 업무 처리 클래스 + */ +public class DefaultWorkHandler { + //개발 작업자 + private String developer; + + public DefaultWorkHandler(String developer) { + this.developer = developer; + } + + //업무 처리 메소드 + public void handle(IdeaRequest ideaRequest) { + System.out.printf("%s 개발자가 업무를 처리했습니다.\n", this.developer); + ideaRequest.setDeveloper(this.developer); + } +} + +public class Main { + public static void main(String[] args) { + DefaultWorkHandler defaultWorkHandler = new DefaultWorkHandler("최재우"); + //업무 처리자 저장 클래스 + IdeaRequest ideaRequest = new IdeaRequest(); + //업무 처리 + defaultWorkHandler.handle(ideaRequest); + //업무 처리자 출력 + ideaRequest.printWorker(); + } +} + +결과 +최재우 개발자가 업무를 처리했습니다. +=================== +개발 : 최재우 +=================== +``` + +위의 코드는 간단하게 `DefaultWorkHandler.handle()`을 통해 개발자가 업무를 처리하는 기능을 구현했다. + +그렇다면 이번엔 `개발 업무`를 진행하기전에 `기획 작업`이 추가돼야한다 가정하자. + +아래 예제는 기존 코드에 기획 작업을 추가하는 2가지의 방법이다. + +```java +1. 기존 handle()에 기획 업무까지 처리하는 코드 + +/** + * 업무처리자 저장 클래스 + */ +public class IdeaRequest { + private String developer; + private String planner; + + public void printWorker() { + System.out.println("==================="); + System.out.printf("개발 : %s\n", this.developer); + System.out.printf("기획 : %s\n", this.planner); + System.out.println("==================="); + } + //...Setter + //...Getter +} + +/** + * 업무 처리 클래스 + */ +public class DefaultWorkHandler { + private String developer; + private String planner; + + public DefaultWorkHandler(String developer, String planner) { + this.developer = developer; + this.planner = planner; + } + //업무 처리 메소드 + public void handle(IdeaRequest ideaRequest) { + //기획 업무를 기존 개발 업무처리 메소드에 같이 처리 + System.out.printf("%s 기획자가 업무를 처리했습니다\n", planner); + //기획자 등록 + ideaRequest.setPlanner(planner); + + //개발 업무 처리 + System.out.printf("%s 개발자가 업무를 처리했습니다.\n", this.developer); + //개발자 등록 + ideaRequest.setDeveloper(this.developer); + } +} + +public class Main { + public static void main(String[] args) { + DefaultWorkHandler defaultWorkHandler = new DefaultWorkHandler("최재우", "박영준"); + IdeaRequest ideaRequest = new IdeaRequest(); + //업무 처리 + defaultWorkHandler.handle(ideaRequest); + //업무 처리자 출력 + ideaRequest.printWorker(); + } +} + +결과 +박영준 기획자가 업무를 처리했습니다 +최재우 개발자가 업무를 처리했습니다. +=================== +개발 : 최재우 +기획 : 박영준 +=================== + +2. 기획 업무를 처리할 DefaultWOrkHandler를 상속한 Handler 클래스 생성 + +public class IdeaRequest { + //IdeaRequest 위와 동일 +} + +/** + * 업무 처리 클래스 + */ +public class DefaultWorkHandler { + private String developer; + + public DefaultWorkHandler(String developer) { + this.developer = developer; + } + //업무 처리 메소드 + public void handle(IdeaRequest ideaRequest) { + System.out.printf("%s 개발자가 업무를 처리했습니다.\n", this.developer); + ideaRequest.setDeveloper(this.developer); + } +} + +/** + * 기획 업무 처리 클래스 + */ +public class PlaningWorkHandler extends DefaultWorkHandler{ + private String planner; + + public PlaningWorkHandler(String developer, String planner) { + //부모 클래스에 개발자 전달 + super(developer); + //기획자 이름 저장 + this.planner = planner; + } + + @Override + public void handle(IdeaRequest ideaRequest) { + //기획 업무 처리 + System.out.printf("%s 기획자가 업무를 처리했습니다.\n", this.planner); + ideaRequest.setPlanner(this.planner); + //개발 업무 호출 + super.handle(ideaRequest); + } +} + +public class Main { + public static void main(String[] args) { + DefaultWorkHandler defaultWorkHandler = new PlaningWorkHandler("최재우", "박영준"); + IdeaRequest ideaRequest = new IdeaRequest(); + //업무 처리 + defaultWorkHandler.handle(ideaRequest); + //업무 처리자 출력 + ideaRequest.printWorker(); + } +} + +박영준 기획자가 업무를 처리했습니다. +최재우 개발자가 업무를 처리했습니다. +=================== +개발 : 최재우 +기획 : 박영준 +=================== +``` + +1번 방법 같은 경우 기존 `handle()` 메소드에 기획 업무까지 같이 처리하게끔 구현된 것을 볼 수 있는데, 이 경우 `단일 책임 원칙(SRP: Single Responsibility Principle)`을 위반하게 된다. + +2번 방법은 `DefaultWorkHandler`를 상속 받은 `PlaningWorkHandler`을 구현함으로써 기존 코드를 수정하지 않고 기획 작업을 추가했으므로 `SRP` 는 만족을 한다. 하지만 내가 사용할 구체적인 클래스 구현체를 클라이언트에서 직접 변경해줘야한다. +예를 들어 **개발만 작업하고 싶으면** `DefaultWorkHandler`, **기획 작업을 추가하고 싶으면**`PlaningWorkHandler`를 사용해야한다는 것 즉, `커플링`이 높아지게 된다. + +또한 추후에 `개발 작업`후 `QA테스트 작업`이 추가되거나, `기획 작업`을 제외하고 `개발 작업`과 `QA테스트`만 진행해야하는 경우마다 각각의 `WorkHandler`를 새로 작성해줘야하므로 매우 복잡해진다. + +이제 `책임 연쇄 패턴`을 적용해보자. + +![Untitled](https://user-images.githubusercontent.com/32676275/156932259-757d5fbb-93be-4305-8704-03c5b1f25e9f.png) + +```java +/** + * 작업 처리자 저장 클래스 + */ +public class IdeaRequest { + private String developer; + private String planner; + private String tester; + + public void printWorker() { + System.out.println("==================="); + System.out.printf("개발 : %s\n", this.developer); + System.out.printf("기획 : %s\n", this.planner); + System.out.printf("QA : %s\n", this.tester); + System.out.println("==================="); + } + //...Setter + //...Getter +} + +/** + * 각 작업의 공통 인터페이스 + */ +public interface WorkHandler { + void handle(IdeaRequest ideaRequest); +} + +/** + * 개발 업무 처리 Handler + */ +class DeveloperWorkHandler implements WorkHandler { + private WorkHandler workHandler; + private String developer; + + public DeveloperWorkHandler(WorkHandler workHandler, String developer) { + //다음 업무로 체이닝할 WorkHandler 객체 + this.workHandler = workHandler; + this.developer = developer; + } + + //업무 처리 메소드 + @Override + public void handle(IdeaRequest ideaRequest) { + System.out.printf("%s 개발자가 업무를 처리했습니다.\n", this.developer); + ideaRequest.setDeveloper(this.developer); + + if(this.workHandler != null) { + //다음 업무 처리 + this.workHandler.handle(ideaRequest); + } + } +} + +/** + * 기획 업무 처리 Handler + */ +public class PlaningWorkHandler implements WorkHandler { + private String planner; + private WorkHandler workHandler; + + public PlaningWorkHandler(WorkHandler workHandler,String planner) { + //다음 업무로 체이닝할 WorkHandler 객체 + this.workHandler = workHandler; + this.planner = planner; + } + + @Override + public void handle(IdeaRequest ideaRequest) { + System.out.printf("%s 기획자가 업무를 처리했습니다.\n", this.planner); + ideaRequest.setPlanner(this.planner); + + if(this.workHandler != null) { + //다음 업무 처리 + this.workHandler.handle(ideaRequest); + } + } +} + +/** + * QA 업무 처리 Handler + */ +public class TestWorkHandler implements WorkHandler{ + private WorkHandler workHandler; + private String tester; + + public TestWorkHandler(WorkHandler workHandler, String tester) { + //다음 업무로 체이닝할 WorkHandler 객체 + this.workHandler = workHandler; + this.tester = tester; + } + + @Override + public void handle(IdeaRequest ideaRequest) { + System.out.printf("%s 테스터가 업무를 처리했습니다.\n", this.tester); + ideaRequest.setTester(this.tester); + + if(this.workHandler != null) { + //다음 업무 처리 + workHandler.handle(ideaRequest); + } + } +} + +/** + * 메인 클래스 + */ +public class Main { + private WorkHandler workHandler; + + public Main(WorkHandler workHandler) { + this.workHandler = workHandler; + } + + public void doWork() { + IdeaRequest ideaRequest = new IdeaRequest(); + //체이닝으로 연결된 workHandler 작업 수행 + this.workHandler.handle(ideaRequest); + //작업자 출력 + ideaRequest.printWorker(); + } + + public static void main(String[] args) { + //체이닝으로 각 handler를 연결 + //기획 -> 개발 -> 테스트 작업 진행 + WorkHandler workHandler = + new PlaningWorkHandler( + new DeveloperWorkHandler( + new TestWorkHandler(null, "홍길동"), "아무개"), "오징어"); + + Main main = new Main(workHandler); + //작업 수행 + main.doWork(); + + //개발 -> 테스트 작업 진행 + WorkHandler workHandler1 = + new DeveloperWorkHandler( + new TestWorkHandler(null, "홍길동"), "아무개"); + + main = new Main(workHandler1); + //작업 수행 + main.doWork(); + } +} +``` + +책임 연쇄 패턴을 적용함으로써 `WorkHandler`를 상속한 각 업무(`Development`, `Planing`, `QA`)를 구현하고 각 구현체에 `WorkHandler` 객체를 생성자에서 받음으로써 체이닝이 된 것을 볼 수 있다. + +이렇게 됨으로써 `클라이언트(Main)`에서는 `WorkHandler`의 구체적인 구현체를 알지 못해도 `handle()` 만 호출함으로써 알아서 체이닝된 업무들이 실행될 것이다. 또한 **필요한 업무만 체이닝하거나 순서도 바꿔서 사용할 수 있게 된다.** \ No newline at end of file diff --git "a/\355\226\211\353\217\231/7\354\243\274\354\260\250-\354\261\205\354\236\204 \354\227\260\354\207\204/summary/\354\261\205\354\236\204 \354\227\260\354\207\204 \355\214\250\355\204\264.md" "b/\355\226\211\353\217\231/7\354\243\274\354\260\250-\354\261\205\354\236\204 \354\227\260\354\207\204/summary/\354\261\205\354\236\204 \354\227\260\354\207\204 \355\214\250\355\204\264.md" new file mode 100644 index 0000000..d2ebaa3 --- /dev/null +++ "b/\355\226\211\353\217\231/7\354\243\274\354\260\250-\354\261\205\354\236\204 \354\227\260\354\207\204/summary/\354\261\205\354\236\204 \354\227\260\354\207\204 \355\214\250\355\204\264.md" @@ -0,0 +1,409 @@ +# 책임 연쇄 패턴 + +> 객체를 가볍게 만들어 메모리 사용을 줄이는 패턴 + +![](https://refactoring.guru/images/patterns/diagrams/chain-of-responsibility/structure-indexed.png) + +**Handler**: 요청을 수신하고 처리객체들의 집합에 전달하는 인터페이스, 집합의 첫 번째 핸들러 정보만 알고 이후 핸들러는 알지 못함 + +**Base Handler**: 모든 핸들러 클래스에 공통적으로 사용 가능한 코드를 입력할 수 있는 옵션 클래스 (Optional) + +**Concrete handlers** : 요청을 처리하는 실제 처리객체 + +## 책임 연쇄 패턴은 언제 사용되는가? + +- **결합을 느슨하게 하고 싶을때.** 요청을 보내는 객체와 처리하는 객체간의 결합도를 낮추기 위해서 사용 + +## 책임 연쇄 패턴 예제 코드 + +아래 예제는 개발자가 개발업무 처리후 작업자를 저장하는 과정을 작성한 코드이다. + +```java +/** + * 업무처리자 저장 클래스 + */ +public class IdeaRequest { + private String developer; + + public void printWorker() { + System.out.println("==================="); + System.out.printf("개발 : %s\n", this.developer); + System.out.println("==================="); + } + //...Setter + //...Getter +} + +/** + * 업무 처리 클래스 + */ +public class DefaultWorkHandler { + //개발 작업자 + private String developer; + + public DefaultWorkHandler(String developer) { + this.developer = developer; + } + + //업무 처리 메소드 + public void handle(IdeaRequest ideaRequest) { + System.out.printf("%s 개발자가 업무를 처리했습니다.\n", this.developer); + ideaRequest.setDeveloper(this.developer); + } +} + +public class Main { + public static void main(String[] args) { + DefaultWorkHandler defaultWorkHandler = new DefaultWorkHandler("최재우"); + //업무 처리자 저장 클래스 + IdeaRequest ideaRequest = new IdeaRequest(); + //업무 처리 + defaultWorkHandler.handle(ideaRequest); + //업무 처리자 출력 + ideaRequest.printWorker(); + } +} + +결과 +최재우 개발자가 업무를 처리했습니다. +=================== +개발 : 최재우 +=================== +``` + +위 코드에서 `DefaultWorkHandler.handle()`은 개발자가 업무 처리하는 기능이다. + +이번엔 `개발 업무`를 진행하기전에 `기획 작업`이 추가된다 해보자. + +아래는 `기획 작업`을 추가하는 2가지의 방법이다. + +```java +1. 기존 handle()에 기획 업무까지 처리하는 코드 + +/** + * 업무처리자 저장 클래스 + */ +public class IdeaRequest { + private String developer; + private String planner; + + public void printWorker() { + System.out.println("==================="); + System.out.printf("개발 : %s\n", this.developer); + System.out.printf("기획 : %s\n", this.planner); + System.out.println("==================="); + } + //...Setter + //...Getter +} + +/** + * 업무 처리 클래스 + */ +public class DefaultWorkHandler { + private String developer; + private String planner; + + public DefaultWorkHandler(String developer, String planner) { + this.developer = developer; + this.planner = planner; + } + //업무 처리 메소드 + public void handle(IdeaRequest ideaRequest) { + //기획 업무를 기존 개발 업무처리 메소드에 같이 처리 + System.out.printf("%s 기획자가 업무를 처리했습니다\n", planner); + //기획자 등록 + ideaRequest.setPlanner(planner); + + //개발 업무 처리 + System.out.printf("%s 개발자가 업무를 처리했습니다.\n", this.developer); + //개발자 등록 + ideaRequest.setDeveloper(this.developer); + } +} + +public class Main { + public static void main(String[] args) { + DefaultWorkHandler defaultWorkHandler = new DefaultWorkHandler("최재우", "박영준"); + IdeaRequest ideaRequest = new IdeaRequest(); + //업무 처리 + defaultWorkHandler.handle(ideaRequest); + //업무 처리자 출력 + ideaRequest.printWorker(); + } +} + +결과 +박영준 기획자가 업무를 처리했습니다 +최재우 개발자가 업무를 처리했습니다. +=================== +개발 : 최재우 +기획 : 박영준 +=================== + +2. 기획 업무를 처리할 DefaultWOrkHandler를 상속한 Handler 클래스 생성 + +public class IdeaRequest { + //IdeaRequest 위와 동일 +} + +/** + * 업무 처리 클래스 + */ +public class DefaultWorkHandler { + private String developer; + + public DefaultWorkHandler(String developer) { + this.developer = developer; + } + //업무 처리 메소드 + public void handle(IdeaRequest ideaRequest) { + System.out.printf("%s 개발자가 업무를 처리했습니다.\n", this.developer); + ideaRequest.setDeveloper(this.developer); + } +} + +/** + * 기획 업무 처리 클래스 + */ +public class PlaningWorkHandler extends DefaultWorkHandler{ + private String planner; + + public PlaningWorkHandler(String developer, String planner) { + //부모 클래스에 개발자 전달 + super(developer); + //기획자 이름 저장 + this.planner = planner; + } + + @Override + public void handle(IdeaRequest ideaRequest) { + //기획 업무 처리 + System.out.printf("%s 기획자가 업무를 처리했습니다.\n", this.planner); + ideaRequest.setPlanner(this.planner); + //개발 업무 호출 + super.handle(ideaRequest); + } +} + +public class Main { + public static void main(String[] args) { + DefaultWorkHandler defaultWorkHandler = new PlaningWorkHandler("최재우", "박영준"); + IdeaRequest ideaRequest = new IdeaRequest(); + //업무 처리 + defaultWorkHandler.handle(ideaRequest); + //업무 처리자 출력 + ideaRequest.printWorker(); + } +} + +박영준 기획자가 업무를 처리했습니다. +최재우 개발자가 업무를 처리했습니다. +=================== +개발 : 최재우 +기획 : 박영준 +=================== +``` + +1번 방법은 기존 `handle()` 메소드에 기획 업무도 처리하도록 했지만, 이 경우 `단일 책임 원칙(SRP: Single Responsibility Principle)`을 위반하게 된다. + +2번 방법은 `DefaultWorkHandler`를 상속 받은 `PlaningWorkHandler`을 구현해 기존 코드가 수정되지 않았으므로 `SRP` 는 만족을 한다. 하지만 사용할 클래스 구현체를 클라이언트에서 직접 변경해줘야한다. + +예를 들어 **개발만 작업하고 싶으면** `DefaultWorkHandler`, **기획 작업을 추가하고 싶으면**`PlaningWorkHandler`를 사용해야한다는 것 즉, `커플링`이 높아지게 된다. + +또 만약 `개발 작업`후 `QA테스트 작업`이 추가되거나, `기획 작업`을 제외하고 `개발 작업`과 `QA테스트`만 진행하는 경우 각각의 `WorkHandler`를 새로 작성해야하므로 복잡해진다. + +이제 `책임 연쇄 패턴`을 적용해보자. + +![Untitled](https://user-images.githubusercontent.com/32676275/156932259-757d5fbb-93be-4305-8704-03c5b1f25e9f.png) + +```java +/** + * 작업 처리자 저장 클래스 + */ +public class IdeaRequest { + private String developer; + private String planner; + private String tester; + + public void printWorker() { + System.out.println("==================="); + System.out.printf("개발 : %s\n", this.developer); + System.out.printf("기획 : %s\n", this.planner); + System.out.printf("QA : %s\n", this.tester); + System.out.println("==================="); + } + //...Setter + //...Getter +} + +/** + * 각 작업의 공통 인터페이스 + * ** Handler ** + */ +public interface WorkHandler { + void handle(IdeaRequest ideaRequest); +} + +/** + * 개발 업무 처리 Handler + * ** ConcreteHandler ** + */ +class DeveloperWorkHandler implements WorkHandler { + private WorkHandler workHandler; + private String developer; + + public DeveloperWorkHandler(WorkHandler workHandler, String developer) { + //다음 업무로 체이닝할 WorkHandler 객체 + this.workHandler = workHandler; + this.developer = developer; + } + + //업무 처리 메소드 + @Override + public void handle(IdeaRequest ideaRequest) { + System.out.printf("%s 개발자가 업무를 처리했습니다.\n", this.developer); + ideaRequest.setDeveloper(this.developer); + + if(this.workHandler != null) { + //다음 업무 처리 + this.workHandler.handle(ideaRequest); + } + } +} + +/** + * 기획 업무 처리 Handler + * ** ConcreteHandler ** + */ +public class PlaningWorkHandler implements WorkHandler { + private String planner; + private WorkHandler workHandler; + + public PlaningWorkHandler(WorkHandler workHandler,String planner) { + //다음 업무로 체이닝할 WorkHandler 객체 + this.workHandler = workHandler; + this.planner = planner; + } + + @Override + public void handle(IdeaRequest ideaRequest) { + System.out.printf("%s 기획자가 업무를 처리했습니다.\n", this.planner); + ideaRequest.setPlanner(this.planner); + + if(this.workHandler != null) { + //다음 업무 처리 + this.workHandler.handle(ideaRequest); + } + } +} + +/** + * QA 업무 처리 Handler + * ** ConcreteHandler ** + */ +public class TestWorkHandler implements WorkHandler{ + private WorkHandler workHandler; + private String tester; + + public TestWorkHandler(WorkHandler workHandler, String tester) { + //다음 업무로 체이닝할 WorkHandler 객체 + this.workHandler = workHandler; + this.tester = tester; + } + + @Override + public void handle(IdeaRequest ideaRequest) { + System.out.printf("%s 테스터가 업무를 처리했습니다.\n", this.tester); + ideaRequest.setTester(this.tester); + + if(this.workHandler != null) { + //다음 업무 처리 + workHandler.handle(ideaRequest); + } + } +} + +/** + * 메인 클래스 + * ** Client ** + */ +public class Main { + private WorkHandler workHandler; + + public Main(WorkHandler workHandler) { + this.workHandler = workHandler; + } + + public void doWork() { + IdeaRequest ideaRequest = new IdeaRequest(); + //체이닝으로 연결된 workHandler 작업 수행 + this.workHandler.handle(ideaRequest); + //작업자 출력 + ideaRequest.printWorker(); + } + + public static void main(String[] args) { + //체이닝으로 각 handler를 연결 + //기획 -> 개발 -> 테스트 작업 진행 + WorkHandler workHandler = + new PlaningWorkHandler( + new DeveloperWorkHandler( + new TestWorkHandler(null, "홍길동"), "아무개"), "오징어"); + + Main main = new Main(workHandler); + //작업 수행 + main.doWork(); + + //개발 -> 테스트 작업 진행 + WorkHandler workHandler1 = + new DeveloperWorkHandler( + new TestWorkHandler(null, "홍길동"), "아무개"); + + main = new Main(workHandler1); + //작업 수행 + main.doWork(); + } +} +``` + +책임 연쇄 패턴을 적용함으로써 `WorkHandler`를 상속한 각 업무(`Development`, `Planing`, `QA`)를 구현하고 각 구현체에 `WorkHandler` 객체를 생성자에서 받음으로써 체이닝이 된 것을 볼 수 있다. + +이렇게 됨으로써 `클라이언트(Main)`에서는 `WorkHandler`의 구체적인 구현체를 알지 못해도 `handle()` 만 호출함으로써 알아서 체이닝된 업무들이 실행될 것이다. 또한 **필요한 업무만 체이닝하거나 순서도 바꿔서 사용할 수 있게 된다.** + +## 패턴의 장/단점 + +장점: + +- 요청에 대한 처리의 순서를 컨트롤 할 수 있다. +- SRP(단일책임원칙) 작업 실행하는 클래스에서 작업을 호출하는 클래스를 분리할 수 있다. +- OCP(개방/폐쇄원칙) 존재하는 클라이언트 코드 파괴 없이 앱 안에서의 새로운 핸들러를 추가할 수 있다. + +단점: + +- 몇몇 응답은 처리되지 않을 수 있습니다. + +## 비슷한 패턴 + +- **책임연쇄패턴, 커맨드패턴, 중제자, 옵저버**는 요청에 대한 발송자와 수신자 연결 방식이 다양하다 + - **책임연쇄패턴**은 잠재적인 리시버중 하나가 처리될때까지 요청을 동적인 리시버체인에 따라서 순차적인 처리를 한다. + + - **커맨드 패턴**은 수신자와 송신자 사이의 단방향의 연결을 설립한다. + + - **중제자 패턴**은 송신자와 수신자를 직접적인 통신은 배제하고 중제자 객체를 통한 간접적인 소통 가능하도록 강제한다. + + - **옵저버 패턴**은 수신자의 전달받은 요청으로부터 동적으로 구독하거나 비구독하는 방식으로 구성한다 +- **책임연쇄패턴**은 **컴포짓패턴**과 함께 사용되는 경우가 많다. 이 경우에는 leaf 컴포넌트에 요청을 주게될때, 모든 부모 컴포넌트의 체인을 통과해서 오브젝트 트리루트로 도달 가능하게 만들 수 있다. + +- **책임 연쇄 패턴의 핸들러**는 **커맨드**로 구현 할 수 있다. 이 경우는 너는 요청(Request)으로 표현되는 동일 컨텍스트 객체에 대해서 다양한 작업들을 실행시킬 수 있다. + 하지만, 요청 자체가 커맨드 객체인 다른 접근 방식이 존재한다. 이 경우에는 체인에 연결되어있는 다른 컨택스트에서 동일한 작업을 수행할 수 있다. + + +- **책임 연쇄 패턴**과 **데코레이터**는 클래스 구조상 비슷한 형식을 가지고 있다 . 두 패턴은 모두 한개의 객체로 실행시키기 위해 재귀적 합성방식을 이용한다. 그러나 몇몇 부분은 확연하게 차이점이 있다. + + + - **책임 연쇄 핸들러**는 각각 서로가 독립적으로 임의의 조작을 실행시킬 수 있다. 또한 언제든지 이런 요청들을 멈출 수도 있다. + + - **데코레이터**들은 기본 인터페이스을 기반으로 일관성을 유지하면서 개체의 동작을 확장할 수 있다. 또한 데코레이터는 요청의 흐름을 끊을 수 없다. + +