Design Pattern for Smalltalk – Visitor

t_Dpsc_chapter05_Visitor_01

패턴을 알아보면서 대부분의 내용은 [디자인 패턴]을 참고하고 있지만 Visitor 패턴만큼은 [디자인 패턴]의 내용을 가능하면 적게 참고하기 바란다. 다만 참고해야 할 키워드가 있다면 “이중 디스패치”일 것이다.

객체지향 3원칙중에 “캡슐화”가 있다. 캡슐화는 객체(또는 클래스) 내부의 데이터에 대한 보호를 지원함으로서 내부구조를 외부로 노출시키지 않는 규칙이다. 하지만 필요에 의해서 이 원칙이 깨져야 한다면 어떨까? 하나의 시나리오를 가정해보자.

1. 필요에 의해 한개의 데이터 클래스를 설계한다.
2. 외부에 제공하기 위해 데이터 클래스의 연산(←메서드)을 추가한다.
3. 또 다른 필요에 의해 데이터 클래스에 다른 연산을 추가한다.

이 경우 3번 항목의 과정을 반복하게 되면 클래스의 메서드는 계속 증가하게 된다. 클래스 내부에서 코드는 스파게티처럼 꼬이게 되며 확장등을 위한 관리가 힘들어질 수도 있다. 게다가 추가되는 연산이 다른곳(객체)에도 쓰여야 할 필요성이 생긴다면 그 때 마다 코드를 복사해서 사용 할 것인가? 이건 그다지 효율적인 유지관리 방법은 아닐것이다.

이제부터 방법을 생각해보자.

데이터를 “가공”하는 연산을 추려서 또 다른 클래스로 분리한 다음에 정리해보자. 이렇게 정리된 클래스가 여러개가 된다면 연산의 종류 자체에서도 공통점이 발견 될 것이다. 그렇다면 발견 된 공통점의 인터페이스만 추려서 추상클래스로 만들고, 연산을 적용해야 할 타입별로 하위클래스를 만들어서 연산의 구체적 내용을 구현하면 하나의 클래스군이 만들어 질 것이다. 이것이 Visitor 패턴이다.

한가지 정말 주의해야할 것이 있다. Visitor 패턴군에는 “알고리즘” 만 존재한다. 실제 데이터는 데이터를 보관하고 있는 별도의 객체에 있을것이다. Visitor객체(클래스)에게 데이터객체가 보관하고 있는 데이터로의 접근경로를 열어주는 순간에 캡슐화는 위배된다. 연산의 재사용과 관리에 중점을 둔다면 Visitor 패턴의 사용이 적절하겠지만, 적용에는 충분한 주의가 뒤따라야 한다는 사실을 염두에 두어야 한다.

Design Pattern for Smalltalk – Template method

t_Dpsc_chapter05_TempleteMethod_01

Template method 패턴은 그 내용을 보면 전체적으로 프로그래밍 할 때의 규칙이 클래스 수준으로 축소된 것이라고 보면 좀 더 이해하기 좋다. Template method 패턴에 대해 [디자인 패턴]에서 언급되어 있듯이 “refactoring of generalise” 라는 표현이 이 패턴에 대한 정확한 표현일 것이다. 기존의 프로그램 코드에서 공통적으로 사용할 수 있는 부분을 추려내고, 이렇게 추려내진 부분을 추상클래스에 정리한다. 그리고 특화되어 구현되어야 하는 부분을 하위클래스에 구현한다. 이렇게 공통부와 비공통부를 클래스 수준으로 구현하는 것이 Template method의 기본이 된다.

추상클래스에 존재하는 Template method 클래스의 내부에는 로직만 존재하며, 로직의 내부에는 메서드들이 나열되어있다. 이렇게 로직이 안쪽에서 사용되는 메서드의 구체적 구현은 하위클래스에서 이루어진다.

Template method상위클래스에는 논리의 흐름만 있을 뿐, 흐름에서 필요한 구체적인 동작의 구현을 하위클래스에서 위임하는 형태가 Template method 패턴이다.

Design Pattern for Smalltalk – Strategy

t_Dpsc_chapter05_Strategy_01

Strategy는 사용자가 라이브러리를 구축할 때 사용하는 일반적 개념과 가장 근접된 패턴이다. Sort(정렬) 알고리즘에는 여러가지가 있다. 수학적, 또는 논리적 차이를 가지는 이 알고리즘에는 대표적으로 Bubble, Quick 등이 있다. 이 알고리즘들을 상황에 맞게 사용할 수 있도록 정리해두고 싶다면 어떤 방법이 가장 좋을까? 이럴때 사용하는 것이 바로 Strategy 패턴이다.

Strategy패턴을 구성하고 싶을 때에는 먼저 대상들에게서 공통분모를 추출해서 추상클래스를 만드는 작업부터 시작하는것이 좋다. Sort 알고리즘은 원본 데이터를 받아 내부에서 정렬을 진행한 후 정렬된 결과를 반환한다. 이렇게 원본 데이터를 받아야 하는 인터페이스를 추상클래스에서 정의한 후 하위클래스에서 실제 동작할 내용을 구현하면 된다. 이렇게 하면 알고리즘을 사용해야 하는 context는 스스로가 원하는 알고리즘을 동일한 인터페이스로 골라서 쓰기만 하면 된다.

Strategy패턴은 그 구조상 State패턴과 유사성을 지닌다. 그렇다면 두 패턴은 어떤 차이가 있을까?

State패턴에서는 State의 하위클래스를 타입으로 취급하고 사용하게 권장한다. 반면 Strategy는 하위클래스를 연산으로 취급한다. Strategy패턴에서는 하위클래스의 추가가 타입의 증가로 취급되는것이 아니라 연산의 종류가 늘어나는 것으로 취급 될 것이다. 그리고 State는 context에서 state의 하위클래스가 가지고 있는 내부구현을 자세히 알지 않아도 반환값만 처리하면 되지만, Strategy는 context에서 Strategy의 하위클래스에 들어있는 내부구현 내용을 가능한 만큼 정확하게 숙지해야한다. 또한 context에서 관리 객체 변수가 참조하는 인스턴스가 상태에 따라 바뀐다면 State 패턴, 필요에 따라 지정해서 사용한다면 Strategy패턴으로 분류할 수 있다.