Base/디자인패턴

커맨드 패턴

findmypiece 2021. 11. 11. 09:51
728x90

커맨드는 "명령"이라는 뜻으로 커맨드 패턴은 명령을 클래스화 하는 것을 의미한다.

 

왜 이런게 필요한가? 결국 확장성을 고려한 것인데 예를들어 로그를 기록하는 기능을 구현한다고 가정하면 일반적으로 Log 클래스를 만들어서 그 안에 fileWrite, DbWrite, ConsoleWrite 메소드를 만들 것이다. 

 

그런데 로그를 엘라스틱 서치에 적재하는 기능이 추가로 필요하게 되었다면 어떨까? Log 클래스에 esWrite 메소드를 만들어도 되지만 이렇게 되면 객체지향 설계원칙 중 개방 폐쇄 원칙 에 위배된다. 확장을 위해 Log 클래스를 변경해야 하기 때문이다.

 

기존 Log 클래스를 변경하지 않고 확장하려면 어떻게 해야 할까? 여기에서 필요한 것이 단일 책임 원칙 이다. 에초에 단일 책임만 가지도록 클래스를 설계 하면 그것을 적절하게 조합해서 사용하면 되기 때문에 확장에는 열려있지만 변화에는 닫혀있게 된다.

 

이에 fileWrite, DbWrite, ConsoleWrite 를 각각의 클래스로 만들어서 각각의 단일 책임만 가지게 하고 Log 클래스에서는 이들에게 명령을 내리는 책임만 가지도록 한다. 명령을 내리는 logging 이라는 메소드 정도만 만들어 놓자.

 

그런데 여러가지 기능을 처리해야 하는 Log 클래스에서 변경이 없게 하려면 어떻게 해야할까? 일단 동적으로 각 기능 클래스를 참조 하게 하려면 생성자 혹은 팩토리 메소드를 통해 각 클래스를 참조하게 하면 된다. 그리고 각 기능 클래스의 메소드 역시 약속된 동일한 명칭을 사용해줘야 한다.

 

이때 필요한 것이 자바의 다형성 구현과 메소드 명칭을 미리 선언할 수 있는 인터페이스이다. Logging 이라는 인터페이스를 만들고 그 안에는 logWrite 라는 메소드 뼈대를 만들어 놓는다. 그리고 fileWrite, DbWrite, ConsoleWrite 각 클래스에서는 Logging 인터페이스를 구현하도록 한다. 

 

이로써 fileWrite, DbWrite, ConsoleWrite 는 Logging 이라는 단일타입으로 처리될 수 있는 다형성을 가지게 되고 Log 클래스의 생성자 또는 팩토리 메소드에서는 Logging 타입을 인자로 받아서 처리하면 된다. 그리고 Log 클래스의 logging 메소드에서는 각 기능 클래스의 logWrite 를 호출하도록 하면 된다.

 

추후 엘라스틱 서치에 적재하는 기능을 추가한다고 하면 다시 Logging 인터페이스를 구현한 esWrite 에 해당하는 클래스만 만들고 Log 클래스 생성시 이를 참조하도록 하면 된다.

 

즉, Log 라는 커맨드 클래스를 통해 객체 지향 설계의 개방 폐쇄 원칙과 단일 책임 원칙이 지켜지게 된다.

 

 

728x90