2016년 1월 24일 일요일

State Pattern (상태 패턴)

의도
  • 객체의 상태에 따라 스스로 행동을 변경할 수 있게 하는 패턴
이럴 때 사용하자.
  • 객체의 행동이 상태에 따라 달라지며, 런타임 시에 행동이 바뀌어야 할 때
  • 다중 분기 조건 처리가 너무 많을 때
장점은?
  • 상태에 따른 행동을 국소화하며, 서로 다른 상태에 대한 행동을 별도의 객체로 관리
  • 상태 전이를 명확하게 만듦
  • 상태 객체는 공유될 수 있음
코드
State 클래스
class State
{
public:
   virtual void Handle() = 0;
};

ConcreteStateA, ConcreteStateB 클래스
class ConcreteStateA : public State
{
public:
   void Handle() {
      cout << "ConcreteStateA" << endl;
   };
};

class ConcreteStateB : public State
{
public:
   void Handle() {
      cout << "ConcreteStateB" << endl;
   };
};

Context 클래스
class Context
{
public:
   Context(State* pState)
      : m_pState(pState) {};
   ~Context() {
      m_pState = NULL;
   };

   void SetState(State* pState) {
      m_pState = pState;
   };
   void Request() {
      m_pState->Handle();
   };
private:
   State* m_pState;
};

실행부분
void main()
{
   State* pConcreteStateA = new ConcreteStateA();
   State* pConcreteStateB = new ConcreteStateB();

   Context* pContext = new Context(pConcreteStateA);
   pContext->Request();

   pContext->SetState(pConcreteStateB);
   pContext->Request();

   delete pConcreteStateA;
   delete pConcreteStateB;
   delete pContext;
}
UML - class 다이어그램
참고
  • GoF의 디자인 패턴(개정판) 재사용성을 지닌 객체지향 소프트웨어의 핵심요소
  • http://joochang.tistory.com/64
  • http://blog.naver.com/gp_jhkim/220519499252
  • http://hunnywind.tistory.com/105

2016년 1월 18일 월요일

겨울 하늘 아래 구름

Strategy Pattern (전략 패턴)

의도
  • 동일 계열의 알고리즘군을 정의하고, 각각의 알고리즘을 캡슐화하며, 이들을 상호 교환이 가능하도록 만드는 패턴
이럴 때 사용하자.
  • 행동이 조금씩 다를 뿐 관련된 많은 클래스들일 존재할 때
  • 알고리즘의 변형이 필요할 때
  • 사용자가 몰라야 하는 데이터를 사용하는 알고리즘이 있을 때
  • 하나의 클래스가 많은 행동을 정의하고, 이런 행동들이 그 클래스의 연산 안에서 복잡한 다중 조건문의 모습을 취할 때
장점은?
  • 동일 계열의 관련 알고리즘군이 생김
  • 서브클래싱을 사용하지 않는 대안임
  • 조건문을 없앨 수 있음
  • 구현의 선택이 가능함
단점은?
  • 서로 다른 전략을 알아야 함
  • Strategy 객체와 Context 객체 사이에 의사소통 오버헤드가 있음
  • 객체 수가 증가함
코드
Strategy 클래스
class Strategy
{
public:
   virtual void Algorithm() = 0;
};

ConcreteStrategyA, ConcreteStrategyB 클래스
class ConcreteStrategyA : public Strategy
{
public:
   void Algorithm() {
      cout << "ConcreteStrategyA" << endl;
   };
};
class ConcreteStrategyB : public Strategy
{
public:
   void Algorithm() {
      cout << "ConcreteStrategyB" << endl;
   };
};

Context 클래스
class Context
{
public:
   Context() {};
   void SetStrategy(Strategy* pStrategy) {
      m_pStrategy = pStrategy;
   };
   void Do() {
      m_pStrategy->Algorithm();
   };
private:
   Strategy* m_pStrategy;
};

실행 부분
void main()
{
   Context* pContext = new Context();

   Strategy* pStrategyA = new ConcreteStrategyA();
   pContext->SetStrategy(pStrategyA);
   pContext->Do();

   Strategy* pStrategyB = new ConcreteStrategyB();
   pContext->SetStrategy(pStrategyB);
   pContext->Do();
   
   delete pStrategyA;
   delete pStrategyB;
   delete pContext;
}

UML - class 다이어그램
참고
  • GoF의 디자인 패턴(개정판) 재사용성을 지닌 객체지향 소프트웨어의 핵심요소

2016년 1월 9일 토요일

Template Method Pattern (템플릿 메서드 패턴)

의도
  • 알고리즘의 뼈대만을 정의하고 각 단계에서 수행할 구체적 처리는 서브클래스 쪽에서 하는 패턴
이럴 때 사용하자.
  • 어떤 한 알고리즘을 이루는 부분 중 변하지 않는 부분을 한번 정의해 놓고 다양해질 수 있는 부분은 서브 클래스에서 정의할 수 있도록 남겨두고자 할때
  • 서브클래스 사이의 공통적인 행동을 추출하여 하나의 공통 클래스에 몰아둠으로써 코드 중복을 피하고 싶을때
코드
AbstractClass클래스
class AbstractClass
{
public:
   virtual void Operation1() = 0;
   virtual void Operation2() = 0;

   /* template method */
   void Operation3() {
      cout << "Operation3" << endl;
   };
};

ConcreteClass클래스
class ConcreteClass : public AbstractClass
{
public:
   void Operation1() {
      cout << "Operation1" << endl;
   };
   void Operation2() {
      cout << "Operation2" << endl;
   };
};

실행부분
void main()
{
   AbstractClass* pClass = new ConcreteClass();

   pClass->Operation1();
   pClass->Operation2();
   pClass->Operation3();

   delete pClass;
}

UML - class 다이어그램
참고
  • GoF의 디자인 패턴(개정판) 재사용성을 지닌 객체지향 소프트웨어의 핵심요소
  • http://psh85a.tistory.com/57

2016년 1월 8일 금요일

Visitor Pattern (방문자 패턴)

의도
  • 객체 구조를 이루는 원소에 대해 수행할 연산을 표현하는 패턴
이럴 때 사용하자.
  • 객체 구조가 다른 인터페이스를 가진 클래스들을 포함하고 있어서 구체적 클래스에 따라 이들 오퍼레이션을 수행하고자 할 때
  • 구별되고 관련되지 않은 많은 오퍼레이션이 객체에 수핼될 필요가 있지만, 오퍼레이션으로 인해 클래스들을 복잡하게 하고 싶지 않을 때
장점은?
  • 새로운 연산을 쉽게 추가 가능
  • 연산자들을 한 군데로 모으고 관련되지 않은 연산을 떼어낼 수 있음
단점은?
  • 데이터 은닉을 깰 수 있음
코드
Element, Visitor 클래스
class Element
{
public:
   virtual void accept(class Visitor& rVisitor) = 0;
};

class Visitor
{
public:
   virtual void visit(class This* pElement) = 0;
   virtual void visit(class That* pElement) = 0;
   virtual void visit(class TheOther* pElement) = 0;
};

This, That, TheOther 클래스
class This : public Element
{
public:
   void accept(Visitor& rVisitor) {
      rVisitor.visit(this);
   };
   string thiss() {
      return "This";
   };
};

class That : public Element
{
public:
   void accept(Visitor& rVisitor) {
      rVisitor.visit(this);
   };
   string that() {
      return "That";
   };
};

class TheOther : public Element
{
public:
   void accept(Visitor& rVisitor) {
      rVisitor.visit(this);
   };
   string theOther() {
      return "TheOther";
   };
};

UpVisitor, DownVisitor 클래스
class UpVisitor : public Visitor
{
   void visit(This* pElement) {
      cout << "do Up on" + pElement->thiss() << endl;
   };
   void visit(That* pElement) {
      cout << "do Up on" + pElement->that() << endl;
   };
   void visit(TheOther* pElement) {
      cout << "do Up on" + pElement->theOther() << endl;
   };
};

class DownVisitor : public Visitor
{
   void visit(This* pElement) {
      cout << "do Down on" + pElement->thiss() << endl;
   };
   void visit(That* pElement) {
      cout << "do Down on" + pElement->that() << endl;
   };
   void visit(TheOther* pElement) {
      cout << "do Down on" + pElement->theOther() << endl;
   };
};

실행부분
void main()
{
   Element* pArrayElement[] = { new This(), new That(), new TheOther() };
   UpVisitor upVisitor;
   DownVisitor downVisitor;

   for each (Element* pElement in pArrayElement) {
      pElement->accept(upVisitor);
   }
   for each (Element* pElement in pArrayElement) {
      pElement->accept(downVisitor);
   }

   for each (Element* pElement in pArrayElement) {
      delete pElement;
   }
}

UML - class 다이어그램
참고
  • GoF의 디자인 패턴(개정판) 재사용성을 지닌 객체지향 소프트웨어의 핵심요소
  • http://pusna25.blog.me/100197705146
  • https://ko.wikipedia.org/wiki/%EB%B9%84%EC%A7%80%ED%84%B0_%ED%8C%A8%ED%84%B4

2016년 1월 6일 수요일

Spring에서 Exception 처리 ( @ExceptionHandler, @ControllerAdvice )

@ExceptionHandler
같은 컨트롤러에 @ExceptionHandler 어노테이션을 적용한 메서드가 존재하면, 스프링은 그 메서드가 익셉션을 처리하도록 한다.
따라서, 컨트롤러에 발생한 익셉션을 직접 처리하고 싶다면 @ExceptionHandler 어노테이션을 적용한 메서드를구현해주면 된다.

@Controller
public class MemberDetailController {
   ...
   @RequestMapping("/member/detail/{id}")
   public String detail(@PathVariable("id") Long memId, Model model) {
      Member member = memberDao.selectById(memId);
      if (member == null) {
         throw new MemberNotFoundException();
      }
      model.addAttribute("member", member);
      return "member/memberDetail";
   }

   @ExceptionHandler(TypeMismatchException.class)
   public String handleTypeMismatchException(TypeMismatchException ex) {
      // ex 사용해서 로그 남기는 등 작업
      return "member/invalidId";
   }

   @ExceptionHandler(MemberNotFoundException.class)
   public String handleNotFoundException() throws IOException {
      return "member/noMember";
   }
}

이렇게하면 컨트롤러에서 에러가 날 경우  익셉션을 전달하는 것이 아니라, 컨트롤러 내부에서 직접 에러를 처리하게 된다.

@ControllerAdvice
@ControllerAdivice는 하나의 컨트롤러가 아닌 여러컨트롤러에서 하나의 익셉션을 처리할 때 사용된다.

@ControllerAdivce("chap13.spring")
public class CommonExceptionHandler {
   @ExceptionHandler(RuntimeException.class)
   private ModelAndView errorModelAndView(Exception ex) {
      ModelAndView modelAndView = new ModelAndView();
      modelAndView.setViewName("/error_common");
      modelAndView.addObject("exception", ex );
      return modelAndView;
   }
}

이렇게 M&V 를 사용하면   뷰와,  모델객체를 같이 보낼 수 있다.

참고
  • http://blog.naver.com/xcv1524/220497274201

2016년 1월 1일 금요일

Decorator Pattern (작성자 패턴)

의도
  • 클래스에게 동적인 기능이나 임무를 추가하는 패턴
이럴 때 사용하자.
  • 기존 객체를 유연성 있게 확장할 때 
장점은?
  • 객체의 추가적인 요건을 동적으로 추가
  • 서브클래스 통해 기능을 유연하게 확장할 수 있는 방법을 제공
단점은?
  • 서브 클래스가 많아지게 되면 관리하기에 복잡할 수 있음 (예] 자바의 I/O 클래스 구성체계)​
  • 상속을 통해 확장할 수 있지만, 디자인 유연성 면에서 좋지 않음
코드
Coffee 클래스
class Coffee
{
public:
   virtual int GetCost() = 0;
   virtual string GetIngredients() = 0;
};

DefaultCoffee 클래스
class DefaultCoffee : public Coffee
{
public:
   virtual int GetCost() {
      return 500;
   };
   virtual string GetIngredients() {
      return "Coffee";
   };
};

CoffeeDecorator 클래스
class CoffeeDecorator : public Coffee
{
public:
   CoffeeDecorator(Coffee* pCoffee) {
      m_pCoffee = pCoffee;
   };
protected:
   Coffee* m_pCoffee;
};

Milk, WhippingCream 클래스
class Milk :public CoffeeDecorator
{
public:
   Milk(Coffee* pCoffee)
      : CoffeeDecorator(pCoffee) {};
   virtual int GetCost() {
      return m_pCoffee->GetCost() + 200;
   };
   virtual string GetIngredients() {
      return m_pCoffee->GetIngredients() + ", Milk";
   };
};

class WhippingCream :public CoffeeDecorator
{
public:
   WhippingCream(Coffee* pCoffee)
      : CoffeeDecorator(pCoffee) {};
   virtual int GetCost() {
      return m_pCoffee->GetCost() + 100;
   };
   virtual string GetIngredients() {
      return m_pCoffee->GetIngredients() + ", Whipping Cream";
   };
};

실행부분
void main()
{
   auto_ptr<Coffee> pCoffee(new DefaultCoffee());
   cout << "-- DefaultCoffee -- " << endl;
   cout << "Cost: " << pCoffee->GetCost() << endl;
   cout << "Ingredients: " << pCoffee->GetIngredients().c_str() << endl;

   auto_ptr<Coffee> pCoffeeDec1(new Milk(pCoffee.get()));
   cout << "-- DefaultCoffee + Milk -- " << endl;
   cout << "Cost: " << pCoffeeDec1->GetCost() << endl;
   cout << "Ingredients: " << pCoffeeDec1->GetIngredients().c_str() << endl;

   auto_ptr<Coffee> pCoffeeDec2(new WhippingCream(pCoffeeDec1.get()));
   cout << "-- DefaultCoffee + Milk + WhippingCream -- " << endl;
   cout << "Cost: " << pCoffeeDec2->GetCost() << endl;
   cout << "Ingredients: " << pCoffeeDec2->GetIngredients().c_str() << endl;
}

UML - class 다이어그램
참고
  • GoF의 디자인 패턴(개정판) 재사용성을 지닌 객체지향 소프트웨어의 핵심요소
  • http://h_proms.blog.me/220383634118