diff --git "a/\352\265\254\354\241\260/7\354\243\274\354\260\250-\355\224\204\353\241\235\354\213\234/hong.md" "b/\352\265\254\354\241\260/7\354\243\274\354\260\250-\355\224\204\353\241\235\354\213\234/hong.md"
index e314637..fa62ab3 100644
--- "a/\352\265\254\354\241\260/7\354\243\274\354\260\250-\355\224\204\353\241\235\354\213\234/hong.md"
+++ "b/\352\265\254\354\241\260/7\354\243\274\354\260\250-\355\224\204\353\241\235\354\213\234/hong.md"
@@ -1452,6 +1452,34 @@ Interceptor에 걸리지 못해 그대로 Enhancer의 프록시 객체로 로직
이는 트랜잭션, AOP, Secruity,Async 에서도 발생할 수 있는 예외상황으로 알아두면 좋을 것 같다.
+
+### 22/03/29 추가 정리
+```
+private:
+DispatcherServlet->InvocableHandlerMethod.doInvoke()-> proxy class ->...
+
+public:
+DispatcherServlet->InvocableHandlerMethod.doInvoke()-> proxy class ->public perform AOP->CglibAopProxy.invokeJoinpoint()-> obtain bean attribute ->..
+```
+Controller의 private 메서드가 호출될 수 있는 것은 reflection을 이용해 메소드를 호출하기 때문에 호출이 될 수 있다.
+
+cglib를 이용하는 AOP가 적용된 클래스라면 private메서드는 호출 될까?
+- aop가 적용하려고 한다면 적용이 되지 않고 원본 메서드가 사용된다.
+- aop가 적용되지 않는 그냥 method 라면 위와 같이 정상적으로 로직이 수행이 가능하다.
+ - 특정 메서드의 AOP적용 유무와 상관없이 클래스가 Enhancer대상이라면 Enhancer를 통해 메서드 수행
+ - cglib는 상속을 이용하기에 public 메서드만 재정의하여 사용되기 때문에 private 메서드는 원본 메서드가 사용된다고 이해할 수 있다.
+ - 하지만, logtrace를 보면 실행주체는 Enhancer객체이다. 어떻게 Enhancer에서 없는 private메서드를 실행할까?
+ - Enhancer는 프록시객체의 SuperClass를 reflection으로 private메서드도 실행이 Enhancer에서 가능하다.
+
+만일, private 메서드에서 의존성이 주입된 객체를 사용하려고하면 null이 주입되어 사용된다. 그 이유는?
+- 만일 public 메서드라면 AOP기능을 수행후 실제 target메서드를 수행하기때문에 의존성이 주입된 실제 빈으로 로직을 정상적으로 수행.
+- private 메서드라면 호출은 되지만 의존성 객체가 null이 되어 NullPointException이 발생할 수 있다.
+ - AOP가 적용되는 메서드라면 실제 target을 통해 메서드가 수행될테지만 적용되지 않는 객체라면 실제 메서드가 빈에서 수행되는 것이 아니라 Enhancer객체에서 로직이 수행된다.
+ - Enhancer는 Proxy객체로 상태를 가지고 있지 않기 때문에 의존성주입된 객체가 null이 되어 발생하는 문제이다.
+
+
+
+
### Reference
diff --git "a/\355\226\211\353\217\231/8\354\243\274\354\260\250-\354\273\244\353\247\250\353\223\234/summary/code.md" "b/\355\226\211\353\217\231/8\354\243\274\354\260\250-\354\273\244\353\247\250\353\223\234/summary/code.md"
new file mode 100644
index 0000000..b1104f6
--- /dev/null
+++ "b/\355\226\211\353\217\231/8\354\243\274\354\260\250-\354\273\244\353\247\250\353\223\234/summary/code.md"
@@ -0,0 +1,412 @@
+## 1. 커맨드 패턴(Command Pattern)이란?
+
+> 요청을 캡슐화 하여 호출자(invoker)와 수신자(receiver)를 분리하는 패턴
+
+요청을 호출하는 쪽과 수신하는 쪽을 커맨드 객체를 사용해서 **디커플링**하여 분리시키는게 핵심이다.
+
+요청을 처리하는 방법이 바뀌더라도, 호출자의 코드는 변경되지 않는다.
+
+코드를 통해 실제로 필요한 상황을 알아보자.
+
+
+
+- `Invoker` (Button) : Command 에서 제공하는 메소드를 실행함
+ - 주로 `execute()` 메소드를 호출하고, 경우에 따라 undo() 와 같은 메소드도 사용
+- `Command` : 구체적인 커맨드를 추상화 시킨 인터페이스
+ - Interface 또는 abstract 로 선언
+- `ConcreteCommand` : 구현체, 상속받은 클래스
+ - 실제로 어떤 Receiver를 사용할지, 요청에 대한 작업을 수행하는 메소드와 파라미터가 필요한지 구현
+- `Receiver (Light & Police)` : 실제 요청에 대한 작업을 수행
+
+위와 같이 커맨드 패턴은 Command 를 재사용할 수 있는 장점이 있고, Command를 로깅한다거나, undo 등 추가적인 작업을 관리하기 쉬워진다.
+
+
+
+
+
+## 2. 코드로 알아보는 커맨드 패턴
+
+### 2-1. 요구사항
+사람인서비스에 이력서를 저장하고 조회하고 삭제하는 서비스를 개발하고자 할때 `사람인 양식`과 `Pdf`를 통한 이력서 생성 서비스를 제공하고 있으며 해당 양식으로 생성한 이력서마다 저장하는 과정에서 내부 파라미터를 셋팅하는 로직이 다르다고 가정을 해보자.
+
+```java
+//이력서 모델
+//편의를 위해 모든 데이터 String 형으로 대체
+public class Resume {
+ private String basicInfo; //기본 정보
+ private String careers; //경력 사항
+ private String educations; //교육 사항
+ private String activities; //대외 활동
+ private String certificates; //자격증
+ private String skills; //보유 기술
+ private String preferential; //우대 사항
+ private String portpolio; //포트폴리오
+ private String selfIntroduction;//자기소개서
+ private String resumeType; //이력서 타입(saramin,pdf)
+ private String pdfFile; //pdf file
+ private String documents; //추가 문서,자료
+}
+
+//사람인 폼 이력서 정보 DTO
+public class SaraminFormResume {
+ private String basicInfo;
+ private String careers;
+ private String educations;
+ private String activities;
+ private String certificates;
+ private String skills;
+ private String preferential;
+ private String portpolio;
+ private String selfIntroduction;
+
+ public Resume toEntity(){
+ return new Resume(basicInfo,careers,educations,activities,certificates,skills,preferential,portpolio,selfIntroduction,
+ "saramin",null,null);
+ }
+}
+
+//PDF 이력서 정보 DTO
+public class FileFormResume {
+ private String basicInfo;
+ private String careers;
+ private String educations;
+ private String pdfFile;
+ private String documents;
+
+ public Resume toEntity(){
+ return new Resume(basicInfo,careers,educations,null,null,null,null,null,
+ null, "pdf",pdfFile,null,documents);
+ }
+}
+
+//이력서 서비스
+@RequiredArgsConstructor
+public class ResumeService {
+ private final ResumeRepository resumeRepository;
+
+ //이력서 저장
+ public void saveResume(Resume resume) {
+ //공통 로직
+ System.out.println("====이력서 저장====");
+ System.out.print("기본정보, 경력사항 등 기본 값 validate와 셋팅");
+
+ //이력서 타입에 따른 개별 비즈니스 로직 수행
+ if (resume.getResumeType().equals("saramin")) {
+ System.out.println("사람인 이력서 제외 item 조회");
+ System.out.println("불러오기 가능한 이력서 리스트 조회");
+ System.out.println("인적성 응시 시험 리스트 조회");
+ }else if(resume.getResumeType().equals("file")) {
+ System.out.println("파일 정보 파라미터 할당");
+ System.out.println("파일 이력서 제외 item 조회");
+ System.out.println("파일 썸네일 추출");
+ System.out.println("파일 서버에 업로드");
+ }
+ resumeRepository.save(resume);
+ }
+}
+
+
+
+//DB이용하는 Repository가 아닌 Stub객체
+//이력서 Repository
+public class ResumeRepository {
+ public static final int SARAMIN_RESUME_ID = 1; //사람인 폼 이력서 id
+ public static final int FILE_RESUME_ID = 2; //File 폼 이력서 id
+
+ //이력서 저장
+ public void save(Resume resume) {
+ System.out.println(resume.getResumeType() + " 타입의 이력서 저장");
+ }
+}
+
+
+//Controller와 같이 Service를 사용하는 객체
+public class Client {
+ public static void main(String[] args) {
+ ResumeService resumeService = new ResumeService(new ResumeRepository());
+
+ //사람인폼으로 이력서 저장
+ resumeService.saveResume(new SaraminFormResume().toEntity());
+ System.out.println();
+
+ //Pdf로 이력서 저장
+ resumeService.saveResume(new FileFormResume().toEntity());
+
+ }
+}
+
+결과 :
+====이력서 저장====
+기본정보, 경력사항 등 기본 값 validate와 셋팅사람인 이력서 제외 item 조회
+불러오기 가능한 이력서 리스트 조회
+인적성 응시 시험 리스트 조회
+saramin 타입의 이력서 저장
+
+====이력서 저장====
+기본정보, 경력사항 등 기본 값 validate와 셋팅파일 정보 파라미터 할당
+파일 이력서 제외 item 조회
+파일 썸네일 추출
+파일 서버에 업로드
+file 타입의 이력서 저장
+```
+
+주어진 요구사항을 필요한 부분만 나타내어 개발해보면 위와 같이 개발 할 수 있을 것이다. 여기서 만약에 `URL`을 통한 이력서 서비스를 추가로 제공해야 한다면 `Service`에 초점을 맞춰서 보면 아래와 같이 코드를 추가해야 할 것이다.
+
+```java
+//새로 추가된 URL폼 이력서 DTO
+public class UrlFormResume {
+ private String basicInfo;
+ private String careers;
+ private String educations;
+ private String url;
+ private String documents;
+
+ public Resume toEntity(){
+ return new Resume(basicInfo,careers,educations,null,null,null,null,null,
+ null, "url",null,url,documents);
+ }
+}
+
+@RequiredArgsConstructor
+public class ResumeService {
+ private final ResumeRepository resumeRepository;
+
+ public void saveResume(Resume resume) {
+ System.out.println("====이력서 저장====");
+ System.out.print("기본정보, 경력사항 등 기본 값 validate와 셋팅");
+ if (resume.getResumeType().equals("saramin")) {
+ System.out.println("사람인 이력서 제외 item 조회");
+ System.out.println("불러오기 가능한 이력서 리스트 조회");
+ System.out.println("인적성 응시 시험 리스트 조회");
+ }else if(resume.getResumeType().equals("file")) {
+ System.out.println("파일 정보 파라미터 할당");
+ System.out.println("파일 이력서 제외 item 조회");
+ System.out.println("파일 썸네일 추출");
+ System.out.println("파일 서버에 업로드");
+ }else if(resume.getResumeType().equals("url")) { //새롭게 추가되는 분기(비즈니스 로직)
+ System.out.println("URL 이력서 제외 item 조회");
+ System.out.println("URL 통해 html 다운");
+ System.out.println("URL 썸네일 추출");
+ System.out.println("파일 서버에 업로드");
+ }
+ resumeRepository.save(resume);
+ }
+}
+
+public class Client {
+ public static void main(String[] args) {
+ //URL로 이력서 저장
+ resumeService = new ResumeService(new UrlResumeCommand(),new ResumeRepository());
+ resumeService.saveResume(new UrlFormResume().toEntity());
+ }
+}
+결과 :
+====이력서 저장====
+기본정보, 경력사항 등 기본 값 validate와 셋팅URL 이력서 제외 item 조회
+URL 통해 html 다운
+URL 썸네일 추출
+파일 서버에 업로드
+url 타입의 이력서 저장
+```
+
+이력서의 종류가 추가될 수록 서비스가 담고있는 비즈니스 로직은 무거워지고 요구사항이 변경될때마다 서비스의 객체가 빈번히 수정이 일어나게 된다.
+
+또한, 수정이 빈번히 발생하게 되면 다른 곳에는 영향이 있는지없는지 체크하기 힘들다.
+
+ 테스트코드를 제아무리 꼼꼼히 작성했다하더라도 많은 객체의 의존성이 묶여있어 단위테스트가 어려워지게 된다.
+
+이를 커맨드 패턴을 이용해서 저장,조회,삭제에 대한 행동을 더 세부객체에게 위임해보자.
+
+
+
+### 2-2. 커맨드 패턴 적용 후
+
+```java
+//Command 인터페이스
+public interface ResumeCommand {
+ void saveResume(); //저장 명령
+}
+
+//Concrete Command
+//사람인 폼 이력서 Command
+@RequiredArgsConstructor
+public class SaraminResumeCommand implements ResumeCommand {
+ private final Resume resume; //Receiver
+ private final ResumeRepository resumeRepository; //Receiver
+
+ //저장 세부 비즈니스로직을 수행
+ @Override
+ public void saveResume() {
+ System.out.print("기본정보, 경력사항 등 기본 값 validate와 셋팅");
+ System.out.println(resume.getResumeType() + " 이력서 제외 item 조회");
+ System.out.println("불러오기 가능한 이력서 리스트 조회");
+ System.out.println("인적성 응시 시험 리스트 조회");
+ resumeRepository.save(resume);
+ }
+}
+
+//Concrete Command
+//파일 폼 이력서 Command
+@RequiredArgsConstructor
+public class FileResumeCommand implements ResumeCommand {
+ private final Resume resume; //Receiver
+ private final ResumeRepository resumeRepository; //Receiver
+
+ //저장 세부 비즈니스로직을 수행
+ @Override
+ public void saveResume(Resume resume) {
+ System.out.print("기본정보, 경력사항 등 기본 값 validate와 셋팅");
+ System.out.println(resume.getResumeType() + " 이력서 제외 item 조회");
+ System.out.println("파일 정보 파라미터 할당");
+ System.out.println("파일 썸네일 추출");
+ System.out.println("파일 서버에 업로드");
+ resumeRepository.save(resume);
+ }
+}
+
+//Concrete Command
+//URL 폼 이력서 Command
+@RequiredArgsConstructor
+public class UrlResumeCommand implements ResumeCommand {
+ private final Resume resume; //Receiver
+ private final ResumeRepository resumeRepository; //Receiver
+
+ //저장 세부 비즈니스로직을 수행
+ @Override
+ public void saveResume(Resume resume) {
+ System.out.print("기본정보, 경력사항 등 기본 값 validate와 셋팅");
+ System.out.println(resume.getResumeType() + " 이력서 제외 item 조회");
+ System.out.println("URL 통해 html 다운");
+ System.out.println("URL 썸네일 추출");
+ System.out.println("파일 서버에 업로드");
+ resumeRepository.save(resume);
+ }
+}
+
+//이력서 서비스
+//Invoker
+@RequiredArgsConstructor
+public class ResumeService {
+ private final ResumeCommand resumeCommand;
+
+ public void saveResume(Resume resume) {
+ System.out.println("====이력서 저장====");
+ resumeCommand.saveResume(); //명령을 통해 비즈니스 로직 수행을 세부객체에게 위임
+ }
+}
+
+public class Client {
+ public static void main(String[] args) {
+ //사람인폼으로 이력서 저장
+ Resume resume = new SaraminFormResume().toEntity();
+ ResumeService resumeService = new ResumeService(new SaraminResumeCommand(resume,new ResumeRepository()));
+ resumeService.saveResume();
+
+ System.out.println();
+
+ //Pdf로 이력서 저장
+ resume = new FileFormResume().toEntity();
+ resumeService = new ResumeService(new FileResumeCommand(resume,new ResumeRepository()));
+ resumeService.saveResume();
+
+ System.out.println();
+
+ //URL로 이력서 저장
+ resume = new UrlFormResume().toEntity();
+ resumeService = new ResumeService(new UrlResumeCommand(resume,new ResumeRepository()));
+ resumeService.saveResume();
+ }
+}
+결과 :
+====이력서 저장====
+기본정보, 경력사항 등 기본 값 validate와 셋팅saramin 이력서 제외 item 조회
+불러오기 가능한 이력서 리스트 조회
+인적성 응시 시험 리스트 조회
+saramin 타입의 이력서 저장
+
+====이력서 저장====
+기본정보, 경력사항 등 기본 값 validate와 셋팅file 이력서 제외 item 조회
+파일 정보 파라미터 할당
+파일 썸네일 추출
+파일 서버에 업로드
+file 타입의 이력서 저장
+
+====이력서 저장====
+기본정보, 경력사항 등 기본 값 validate와 셋팅url 이력서 제외 item 조회
+URL 통해 html 다운
+URL 썸네일 추출
+파일 서버에 업로드
+url 타입의 이력서 저장
+```
+
+
+
+
+
+## 3. 장점과 단점
+
+### 3-1. 장점
+
+- 기존 코드를 변경하지 않고 새로운 Command를 만들 수 있음 `(OCP 원칙)`
+- 수신자(Receiver)의 코드가 변경되어도, 호출자(Invoker)의 코드는 변경되지 않음 `(단일책임원칙)`
+- Command 객체를 로깅, DB에 저장, 네트워크로 전송하는 등 다양한 방법으로 활용 가능
+
+
+
+### 3-2. 단점
+
+- 대부분의 디자인 패턴가 마찬가지로 코드가 복잡하고 클래스가 많아짐
+
+
+
+
+
+## 4. Command 패턴과 State 패턴과의 비교
+
+공부를 하면서 `전략 패턴, 커맨드 패턴, 상태 패턴`이 비슷하다고 생각했는데, 이 3개 패턴의 다이어그램을 보면서 차이점을 간단히 정리했다.
+
+
+
+### 4-1. 전략 패턴
+
+[](https://user-images.githubusercontent.com/79291114/153312563-a830529c-8f3e-47f8-b047-9c84225f3401.PNG)
+
+여러 알고리즘을 캡슐화하고 상호 교환 가능하게 만드는 패턴
+
+- 여러 알고리즘을 `상호 교환` 한다는 것은 이미 알고리즘이 실행되는 것은 정해져있고 해당 알고리즘만 교체해준다는 의미입니다.
+- 다이어그램을 보면, **Client가 ConcreteStrategy를 교체**하는 것을 볼 수 있습니다.
+- 즉, **행동이 정해져 있는 상태에서 어떠한 방법으로 수행**할지만 달라집니다.
+
+
+
+### 4-2. 커맨드 패턴
+
+[](https://user-images.githubusercontent.com/79291114/153312559-5b068040-1e19-493c-a680-499744f56f08.PNG)
+
+요청을 캡슐화하여 호출자와 수신자를 분리하는 패턴
+
+- 호출자와 수신자를 분리한다는 것은 `명령(호출자)`과 `행동(수신자)`을 분리한다는 의미입니다.
+- 다이어그램을 보면, **Invoker에 따라서 다양한 Receiver가 호출**되는 것을 알 수 있습니다.
+- 즉, **명령에 따라서 다른 행동을 수행**한다는 것입니다.
+
+
+
+### 4-3. 상태 패턴
+
+[](https://user-images.githubusercontent.com/79291114/153312562-2f70656c-3cd2-4537-8acd-5bfeea7dcfe6.PNG)
+
+객체 내부 상태 변경에 따라 객체의 행동이 달라지는 패턴
+
+- 말 그대로 **객체 내부 상태에 따라서 다른 행동을 수행**한다는 것입니다.
+- 다이어그램을 보면, **Client가 changeState로 상태를 변경해줌에 따라 ConcreteState가 바뀌면서 다른 행동**을 하게됩니다.
+
+
+
+
+
+## 5. 마치며
+
+일단 전략 패턴, 커맨드 패턴, 상태 패턴과 같이 비슷한 패턴은 생김새로 구분하는 것이 아니라, 목적으로 구분해야 한다.
+
+커맨드 패턴은 명령에 따라 커맨드 구현체를 교체하여 다른 행동을 할 수 있기 때문에 유용하게 사용할 수 있다.
+