CSE/Design Pattern 검색 결과

20개 발견
  1. 미리보기
    2015.06.13 - Palpit

    [Design Pattern] 전략(Strategy) 패턴 - 디자인 패턴

  2. 미리보기
    2015.06.13 - Palpit

    [Design Pattern] 메멘토(Memento) 패턴 - 디자인 패턴

  3. 미리보기
    2015.06.13 - Palpit

    [Design Pattern] 커멘드(Command) 패턴 - 디자인 패턴

  4. 미리보기
    2015.06.13 - Palpit

    [Design Pattern] 상태(State) 패턴 - 디자인 패턴

  5. 미리보기
    2015.06.13 - Palpit

    [Design Pattern] 옵저버(Observer) 패턴 - 디자인 패턴

  6. 미리보기
    2015.06.13 - Palpit

    [Design Pattern] 중재자(Mediator) 패턴 - 디자인 패턴

  7. 미리보기
    2015.06.13 - Palpit

    [Design Pattern] 반복자(Iterator) 패턴 - 디자인 패턴

  8. 미리보기
    2015.06.13 - Palpit

    [Design Pattern] 인터프리터(Interpreter) 패턴 - 디자인 패턴

조회수 확인

Pattern #20  전략 패턴




 장단점이 서로 다른 여러 알고리즘들이 존재하는 상황에서 최적의 알고리즘을 선택해서 사용할 때




 패턴 요약 

  - 알고리즘들을 객체로 만들고 일반화

  - Client가 알 필요가 없거나, 알아서는 안 되는 자료를 알고리즘에 사용할 때



 

 동기

  

 당신이 이번에 맡은 일은 보안 시스템을 개발하는 작업이다. 보안 시스템의 핵심으로 암호화 알고리즘이 사용된다. 시스템을 설계할 때 고려해야 될 사항으로는 각 인증기관에 따라 서로 다른 암호화 알고리즘을 사용해야 되며, 또 기술의 발전에 따라 알고리즘을 교체하여야 한다는데 있다. 어떻게 설계할 것인가?

 

 










 기본적인 방법










 기본적인 방법

  - 알고리즘들을 객체로 만들고 일반화 한다.
     * 알고리즘 사용 객체와 알고리즘 객체와의 결합이 줄어든다.  
     * 기존 코드 수정 없이, subclassing을 통하여 새로운 알고리즘을 추가할 수 있다.








 의도

  - 동일한 용도로 사용되는 알고리즘들을 객체로 만들어 서로 교체 할 수 있도록 한다. Strategy는 알고리즘 사용객체와 독립적으로 알고리즘을 변경시킬 수 있음.

 별명

  - Policy









 적용범위

  - 많은 연관된 클래스들이 단지 행위(behavior)만 서로 다를 때, Strategy 패턴을 사용함으로써 하나의 클래스에 적절한 행위를 설정할 수 있다.
   - 장단점이 서로 다른 여러 알고리즘들이 존재하는 상황에서 최적의 알고리즘을 선택해서 사용할 때 유용하다.

 결과

  - 관련된 알고리즘의 패밀리
    * Strategy 클래스 구조는 Context 객체가 사용할 알고리즘 패밀리를 정의한다.
   - subclassing 이외의 다른 방법
    *  다른 알고리즘을 사용하기 위하여 Context 객체를 subclassing할 수 있다. 그러나, 이 경우 각 행위가 특정 sub-class와 묶여지기 때문에 이해하거나 확장 및 관리하기 힘들어진다.
   - 조건문을 제거






예제.




PaymentStrategy.java

 

1
2
3
4
5
6
7
package strategy;
 
public interface PaymentStrategy {
    public void pay(int amount);
}
 
 
cs





CreditCardStrategy.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
package strategy;
 
public class CreditCardStrategy implements PaymentStrategy {
 
    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;
 
    public CreditCardStrategy(String name, String cardNumber, String cvv,
            String dateOfExpiry) {
        this.name = name;
        this.cardNumber = cardNumber;
        this.cvv = cvv;
        this.dateOfExpiry = dateOfExpiry;
    }
 
    public void pay(int amount) {
        System.out.println(amount + " paid with credit/debit card");
    }
 
}
 
cs





PaypalStrategy.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
package strategy;
 
public class PaypalStrategy implements PaymentStrategy {
 
    private String emailId;
    private String password;
 
    public PaypalStrategy(String email, String password) {
        this.emailId = email;
        this.password = password;
    }
 
    public void pay(int amount) {
        System.out.println(amount + " paid using Paypal.");
    }
 
}
 
cs





Item.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 
package strategy;
 
public class Item {
    private String upcCode;
    private int price;
 
    public Item(String upcCode, int price) {
        this.upcCode = upcCode;
        this.price = price;
    }
 
    public String getUpcCode() {
        return upcCode;
    }
 
    public void setUpcCode(String upcCode) {
        this.upcCode = upcCode;
    }
 
    public int getPrice() {
        return price;
    }
 
    public void setPrice(int price) {
        this.price = price;
    }
 
}
 
cs




ShoppingCart.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 
package strategy;
 
import java.util.ArrayList;
import java.util.List;
 
public class ShoppingCart {
    List<Item> items;
 
    public ShoppingCart() {
        this.items = new ArrayList<Item>();
    }
 
    public void addItem(Item item) {
        this.items.add(item);
    }
 
    public void removeItem(Item item) {
        this.items.remove(item);
    }
 
    public int calculateTotal() {
        int sum = 0;
 
        for (Item item : items) {
            sum += item.getPrice();
        }
 
        return sum;
    }
 
    public void pay(PaymentStrategy paymentMethod) {
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}
 
cs





StrategyMain.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
package strategy;
 
public class StrategyMain {
    public static void main(String args[]) {
        ShoppingCart cart = new ShoppingCart();
 
        Item item1 = new Item("1234"10);
        Item item2 = new Item("5678"40);
 
        cart.addItem(item1);
        cart.addItem(item2);
 
        cart.pay(new PaypalStrategy("myemail@exam.com""mypwd"));
 
        cart.pay(new CreditCardStrategy("myName""111333""33432""04/17"));
    }
}
 
cs








다른 카테고리의 글 목록

CSE/Design Pattern 카테고리의 포스트를 톺아봅니다
조회수 확인

Pattern #19  메멘토 패턴



 객체의 상태를 저장해두었다가 복원해야 될 경우 사용





 패턴 요약 
  - 오리지널 객체는 본래의 기능에 충실하고 메멘토는 상태 정보와 관리를 전답하면서 캡슐화되어 독립적
  - 상태 역할만 분리


 
 동기

  

 게임회사에 다니는 당신에게 새로 맡겨진 일은 바둑 프로그램 개발 작업이다. 게임 인공지능 부분은 다른 팀에서 맡기로 하였고, 당신은 사용자 인터페이스와 바둑 무르기, 복기하기 등과 같은 기능을 개발하여야 한다. 바둑 무르기 기능의 경우, 사용자가 두기 이전 상태로 되돌려야 하며 복기 기능은 게임의 처음부터 진행된 때 까지 바둑판 상태를 차례대로 표현할 수 있어야 한다. 이렇게 객체의 상태를 저장해두었다가 복원해야 될 경우 당신은 어떻게 객체지향설계를 할 것인가?

 

 









 





  바둑 게임 분석
   - 필요 정보
     * 바둑돌 배치: int board[19][19]; // 0: none, -1: black, 1: white
     * 흰돌 사석수: int whiteDeadNum;
     * 검은돌 사석수: int blackDeadNum;
     * 다음 둘 차례: int whoseTurn; // -1:black's turn, 1: white's turn
     * 패 위치: paePosX, paePosY;











  해결 방안 1:
   - 보관할 필요가 있는 정보를 따로 뽑아서 객체로 만들어 이를 저장하거나 복원함














   해결 방안 2:
   - 원 소유자를 제외한 다른 객체에서 상태정보(객체)에 대한 접근을 제한하기 위하여 Memento객체를 만든다.
    - Memento 객체의 GoState를 포함한다.
    - Memento 객체의 생성과 내부 GoState 객체 접근은 원 소유자인 GoBoard에서만 할 수 있다.
    - GoBoard는 Memento를 생성하고, 지정된 Memento로 복원하는 함수를 구현한다.
     * CreateMemento(): 내부 정보를 외부 객체(Memento)화
     * SetMemento(Memento *m): m에 저장되어있는 상태로 복원

















 - 접근 제한 방법
   * in C++: friend keyword 사용












 의도
   - 객체지향 개념인 캡슐화(Encapsulation)을 어기지 않으면서, 특정 객체의 상태정보를 나중에 복원하기 위하여 해당 정보를 외부에 상태객체로 표현한다.
  


 별명
   - Token



 적용범위
   - 어떤 객체의 특정 시점에 대한 상태 정보가 나중에 복원되기 위해 저장되어야 할 경우
    - 객체의 상태정보를 직접 접근하는 것이 정보 은닉이나 캡슐화 원리를 깨뜨릴 때.



 결과
   - 캡슐화 범위 안으로 유지
      * Originator 객체 이외의 객체에서 Memento 객체의 내부 정보를 접근하는 것을 제한
    - Originator 단순화
      * Client가 내부상태정보를 직접 접근하지 않으면서도 Memento 객체를 이용하여 Originator를 예전 상태로 복원할 수 있다.
    - 메멘토 사용이 부담이 될 수도 있음
      * Memento 객체의 생성이 자주 일어나거나 내부 상태정보가 많은 경우
    - 인터페이스 정의
      * 캡슐화를 위해 Memento 객체의 내부 정보 접근을 제한하는 것은 특정 프로그래밍언어에서는 어려울 수도 있음





Life.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package memento;
 
public class Life {
    private String time;
 
    public void setTime(String time) {
        System.out.println("Setting time to " + time);
        this.time = time;
    }
 
    public Memento saveToMemento() {
        System.out.println("Saving time to Memento");
        return new Memento(time);
    }
 
    public void restoreFromMemento(Memento memento) {
        time = memento.getSavedTime();
        System.out.println("Time restored from Memento: " + time);
    }
 
    public static class Memento {
        private final String time;
 
        public Memento(String time) {
            this.time = time;
        }
 
        public String getSavedTime() {
            return time;
        }
    }
}
 
 
cs





Memento.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
package memento;
 
import java.util.ArrayList;
import java.util.List;
 
public class MementoMain {
    public static void main(String[] args) {
        List<Life.Memento> savedTimes = new ArrayList<Life.Memento>();
 
        Life life = new Life();
 
        life.setTime("2000 B.C");
        savedTimes.add(life.saveToMemento());
        life.setTime("2000 A.D");
        savedTimes.add(life.saveToMemento());
        life.setTime("3000 A.D");
        savedTimes.add(life.saveToMemento());
        life.setTime("4000 A.D");
        savedTimes.add(life.saveToMemento());
 
        life.restoreFromMemento(savedTimes.get(0));
    }
}
 
 
cs







  





다른 카테고리의 글 목록

CSE/Design Pattern 카테고리의 포스트를 톺아봅니다
조회수 확인

Pattern #18  커멘드 패턴




 서비스를 호출할 때 융통성을 높이려고 사용 (ex: undo Operation)




 패턴 요약 

  - 오퍼레이션을 클래스로 정의



 

 동기

  

 PDA’s GUI System 개발 프로젝트에 참여한 당신이 맡은 업무는 window main-menu 부분의 설계이다. 각 application은 mainmenu를

가지고 있고, main-menu의 각 menu 들은 여러 개의 menu-item 을 가 지 고 있 다 . 사용자가 특정 menu-item 을 선택하면 해당 menu-item에 연동된 기능이 수행된다. 당신은 어떤 식으로 설계할 것 인가?

 

 




 



 어플리케이션 모델링 




 





 어플리케이션 모델링2 

 - 기능요청(예: '문서열기') 자체를 객체화 - Command
 - 기능요청을 원하는 각 객체에 해당 Command 객체 연결
 - 기능 요청을 원하는 각 객체가 선택될 때 연결된 Command 객체 실행 - commandExecute()








 

 Command class hierarchy 

 1) PasteCommand: 현 위치에 Clipboard 내용 붙여 넣기 => 다른 객체(document)에 요청 보내기
 2) OpenCommand: 문서열기 => 몇 개의 연산 조합으로 기능 수행
 









 Command class hierarchy 

 3) MacroCommand: 다른 Command 객체들을 연속 실행







 의도 

  - Encapsulate a request as an object
  - 기능요청을 객체화함으로써, 동적으로 기능설정을 바꾸거나, 실행된 기능들을 기록하거나 실행된 작업들을 재복구 시킬 수 있다.

 별칭

  - Action, Transaction






 적용범위

  - MenuItem 객체의 경우처럼, 객체에 수행되어야 할 행위(acion)를 동적으로 설정할 때
  - 작업 수행을 요청한 시점과 실제 작업이 수행되어야 할 시점을 다르게 할 필요가 있을 때
  - Undo 기능을 지원하고자 할 때
  - System의 기능수행 정도를 기록하고 싶을 때 => 각 Command 객체들이 수행될 때 마다 자신의 기록을 남김
  - 기본적인 행위들을 조합하여 더욱 복잡한 행위를 실핼하고자 할 때 => MacroCommand 사용
 

 결과

  - 작업 수행을 요청하는 객체와 실제 작업을 수행하는 객체를 분리한다.
  - 작업 요청 자체가 객체가 되기 때문에, 다른 객체처럼 '작업 요청' 자체를 저장하고 복구하고, 확장할 수 있다.  
  - 기본적인 행위들을 조합하여 더욱 복잡한 행위를 실행하고자 할 때
  - 기존 코드의 변경 없이 새로운 Command를 추가할 수 있다.







예제.




Command.java
1
2
3
4
5
6
7
 
package command;
 
public interface Command {
    public void execute();
}
 
cs





Switch.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
package command;
 
import java.util.ArrayList;
import java.util.List;
 
public class Switch {
    private List<Command> history = new ArrayList<Command>();
 
    public Switch() {
    }
 
    public void storeAndExecute(Command command) {
        this.history.add(command);
        command.execute();
    }
}
 
cs





Computer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
package command;
 
public class Computer {
 
    public void shutDown() {
        System.out.println("Computer is shut down");
    }
 
    public void restart() {
        System.out.println("Computer is restarted");
    }
}
 
cs




ShutDownCommand.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
package command;
 
public class ShutDownCommand implements Command {
 
    private Computer computer;
 
    public ShutDownCommand(Computer computer) {
        this.computer = computer;
    }
 
    public void execute() {
        computer.shutDown();
    }
 
}
 
cs




RestartCommand.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
package command;
 
public class RestartCommand implements Command {
 
    private Computer computer;
 
    public RestartCommand(Computer computer) {
        this.computer = computer;
    }
 
    public void execute() {
        computer.restart();
    }
 
}
 
cs




CommandMain.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
package command;
 
public class CommandMain {
 
    public static void main(String[] args) {
        Computer computer = new Computer();
        Command shutdown = new ShutDownCommand(computer);
        Command restart = new RestartCommand(computer);
 
        Switch s = new Switch();
 
        String str = "shutdown";
 
        if (str.equals("shutdown")) {
            s.storeAndExecute(shutdown);
        } else {
            s.storeAndExecute(restart);
        }
    }
 
}
 
cs















다른 카테고리의 글 목록

CSE/Design Pattern 카테고리의 포스트를 톺아봅니다
조회수 확인

Pattern #17  상태 패턴




 객체의 상태에 의하여 결정된 방법으로 객체를 동작하게 할 때 사용




 패턴 요약 

  - 상태 객체를 따로 만들어 포함하게 하고, 상태 객체에게 위임하여 동작하게 함



 

 동기

  

 당신은 새로운 프로젝트의 프로그램 reviewer 책임을 맡았다. Reviewer로 당신은 팀원들이 개발한 핵심 코드를 살펴보고, 논리상의 문제점이나 좋지 않은 설계구조를 지적해 주어야 한다. 오늘 살펴본 코드에는, 특정 객체가 자신의 상태에 따라 다른 행동을 하기 위하여 if 문장을 많이 사용하였다. 그러다 보니, 함수의 크기가 커지고 객체상태가 많은 경우 해당 객체의 구현이 더욱 복잡해졌다. 개발자에게 조언해줄 해결방법은?

 

 







     



해결방안 

  - 객체의 가능한 상태 개수 만큼 State class를 작성한다.

 



 


  - 일반적으로 State class의 interface는 특정 상태에 따라 객체의 행위가 달라지는 함수들을 포함한다.





  - TCPConnection class와 State Class에 자신의 상태를 변화시킬 수 있는 ChangeState() 메서드를 추가한다.








  - State 객체가 TCPConnection 객체를 알수 있도록 한다.

    * 함수를 호출할 때 인자로 TCPConnection 객체를 넘기던가, 혹은 각 State 객체가 생성될 때 TCPConnection 객체 reference를 가지든가. -> 여기서는 전자로








 - 기존 객체의 상태에 의존적인 함수는 State 객체로의 deleation으로 구현한다.








- TCPConnection 객체의 상태변화는 내부 함수나 State 객체에서만 일으킬 수 있다(ChangeState()를 private으로)


 



 



- TCPConnection 객체 상태 변화 예







- State 객체가 독자적인 정보를 가지지 않는다면, 객체를 여러 개 가질 필요는 없다. 

  * State 객체는 특정 객체의 행위들을 각 상태에 따라 모아 놓은 것이기 때문에 단순 함수 집합으로 간주해도됨.

  * Singleton pattern 활용

  * 앞의 예에서 Singleton pattern을 사용한 모습






의도 

  - 객체의 내부 상태가 변경되었을 때 그에 따라 객체의 행위도 변경되게 한다.(마치 다른 class의 객체가 된 것 처럼)


별칭 

  - Objects for States


적용범위

  - 객체의 행위가 해당 객체의 상태에 따라 달라질 때

  - 객체의 함수 코드가 객체의 상태에 따라 큰 부분의 조건 문장으로 구성되어 있을 때(if 문장, switch 문장)













예제1.




State.java

 

1
2
3
4
5
6
7
 
package state1;
 
public interface State {
    public void saySomething(StateContext sc);
}
 
cs





Rich.java

 

1
2
3
4
5
6
7
8
9
10
11
12
 
package state1;
 
public class Rich implements State {
 
    public void saySomething(StateContext sc) {
        System.out.println("I'm rich currently, and play a lot");
        sc.changeState(new Poor());
    }
 
}
 
cs





Poor.java

 

1
2
3
4
5
6
7
8
9
10
11
12
 
package state1;
 
public class Poor implements State {
 
    public void saySomething(StateContext sc) {
        System.out.println("I'm poor currently, and spend much time working");
        sc.changeState(new Rich());
    }
 
}
 
cs





StateContext.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
package state1;
 
public class StateContext {
    private State currentState;
 
    public StateContext() {
        currentState = new Poor();
    }
 
    public void changeState(State newState) {
        this.currentState = newState;
    }
 
    public void saySomething() {
        this.currentState.saySomething(this);
    }
}
 
cs





StateMain.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
package state1;
 
public class StateMain {
 
    public static void main(String[] args) {
        StateContext sc = new StateContext();
        
        sc.saySomething();
        sc.saySomething();
        sc.saySomething();
        sc.saySomething();
        
    }
 
}
 
cs















예제2.





State.java

 

1
2
3
4
5
6
7
 
package state2;
 
public interface State {
    public void doAction();
}
 
cs





TVContext.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
package state2;
 
public class TVContext implements State {
 
    private State tvState;
 
    public void setState(State state) {
        this.tvState = state;
    }
 
    public State getState() {
        return this.tvState;
    }
 
    public void doAction() {
        this.tvState.doAction();
    }
 
}
 
cs





TVStartState.java

 

1
2
3
4
5
6
7
8
9
10
11
 
package state2;
 
public class TVStartState implements State {
 
    public void doAction() {
        System.out.println("TV is turned ON");
    }
 
}
 
cs





TVStopState.java

 

1
2
3
4
5
6
7
8
9
10
11
12
 
package state2;
 
public class TVStopState implements State {
 
    @Override
    public void doAction() {
        System.out.println("TV is turned OFF");
    }
 
}
 
cs





StateMain.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
package state2;
 
public class StateMain {
 
    public static void main(String[] args) {
        TVContext context = new TVContext();
 
        State tvStartState = new TVStartState();
        State tvStopState = new TVStopState();
 
        context.setState(tvStartState);
        context.doAction();
 
        context.setState(tvStopState);
        context.doAction();
    }
 
}
 
cs













다른 카테고리의 글 목록

CSE/Design Pattern 카테고리의 포스트를 톺아봅니다
조회수 확인

Pattern #16  옵저버 패턴



 한 객체에 의하여 영향을 받는 객체들을 정리하는데 사용






 패턴 요약 

  - 단일 객체가 영향받는 객체 집합에 대하여 같은 이름의 메소드를 호출하여 구현

  - 관찰 대상 객체가 관찰하는 객체가 몇 개인지 어떤 클래스인지 모름



 

 동기


  

  당신은 기업정보 입출력 프로그램을 개발 중이다. 이 프로그램을 이용하여 사용자들은 DB에 저장되어 있는 기업정보(월 판매액, 매출

증가량, …)를 여러 가지 형태(도표, 꺾은선그래프, 막대그래프,..)로 볼 수 있어야 한다. 또한 관리자들이 특정 기업정보를 갱신한다면

해당 정보를 보여주고 있는 모든 View들은 변경된 정보를 다시 반영하여 보여 주어야 한다 . 기업정보(Model) 과 보여주는

화면(View)과의 관계를 어떻게 설계할 것인가?






 

 

 



 

 해결방안

  - Model(data)이 변경되면 이를 각 view(화면)들에게 알려줌

  - Model은 자신의 정보변경에 대한 notification을 받기를 원하는 뷰들에 대한 레퍼런스를 가지고 있어야 한다.

















해결방안2

  - 정보변경 통보를 받은 뷰들은 모델에게서 변경된 정보를 얻어옴

  - 각 뷰들은 자신이 필요로 하는 모델에 대한 레퍼런스를 가지고 있으며, 모델에게 원하는 정보를 얻어 올 수 있다.













해결방안3























해결방안4

 - Model class도 향후 확장을 고려하여 class hierarchy로 구성

 - Observer pattern에서는 통지하는 역할을 Subject, 통지 받는 역할을 Observer라고 얘기함.







 









의도

 - 한 객체의 상태가 변하면 관련된 다른 모든 객체들이 해당 상태변화를 알수 있도록 객체들 간의 one-to-many 의존관계를 정의

 




별칭

 - Dependents, Publish-Subscribe





적용범위

 - 시스템의 한 부분이 다른 부분에 의존적일 때, 양자를 개별적인 객체로 만들고, Observer pattern을 적용하면 독립성과 재사용성을 높일 수 있다.

 - 한 객체의 상태가 변경되면 다른 객체들도 따라 변경될 필요가 있을때 

 - 얼마나 많은 객체들이 따라서 변경되어야 하는지 알 필요가 없을 때

 - 변경을 알리는 객체와 변경을 통지 받는 객체간의 연결강도를 줄일 때





결과

 - Subject객체와 Observer객체간의 coupling을 줄임

   * Subject객체는 단지 Observer 객체 list를 가지고 있다는 정도만 알면 된다.

   * Subject class와 Observer class가 서로 독립적으로 변경 및 확장될 수 있다.

 - Broadcast 통신에도 이용 가능

   * Observer 객체들이 원하는 subject 객체에 등록하지 않고, subject의 상태가 변화되면 전체 객체들에게 상태변화를 broadcast함

 - 예상치 못한 updates 발생가능

    * 관찰자 객체들(Observers) 간에는 상호존재를 인식하지 못하기 때문에, 한 Subject 객체의 상태변화가 전체적으로 어느 정도 만큼의 Observer 변화 비용이 드는지 알지 못함






예제 1.




Subject.java

1
2
3
4
5
6
7
8
9
10
11
package observer1;
 
public interface Subject {
    public void registerObserver(Observer o);
 
    public void removeObserver(Observer o);
 
    public void notifyAllObservers();
}
 
 
cs





Observer.java

1
2
3
4
5
6
7
 
package observer1;
 
public interface Observer {
    public void update(Subject s);
}
 
cs





HeadHunter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 
package observer1;
 
import java.util.ArrayList;
 
public class HeadHunter implements Subject {
 
    private ArrayList<Observer> userList;
    private ArrayList<String> jobs;
 
    public HeadHunter() {
        userList = new ArrayList<Observer>();
        jobs = new ArrayList<String>();
    }
 
    public void registerObserver(Observer o) {
        userList.add(o);
    }
 
    public void removeObserver(Observer o) {
 
    }
 
    public void notifyAllObservers() {
        for (Observer o : userList) {
            o.update(this);
        }
    }
 
    public void addJob(String job) {
        this.jobs.add(job);
        notifyAllObservers();
    }
 
    public ArrayList<String> getJobs() {
        return jobs;
    }
 
    public String toString() {
        return jobs.toString();
    }
 
}
 
cs




JobSeeker.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
package observer1;
 
public class JobSeeker implements Observer {
 
    private String name;
 
    public JobSeeker(String name) {
        this.name = name;
    }
 
    public void update(Subject s) {
        System.out.println(this.name + " got notified");
 
        System.out.println(s);
    }
 
}
 
cs




ObserverMain.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
package observer1;
 
public class ObserverMain {
 
    public static void main(String[] args) {
        HeadHunter hh = new HeadHunter();
 
        hh.registerObserver(new JobSeeker("Kim"));
        hh.registerObserver(new JobSeeker("Lee"));
        hh.registerObserver(new JobSeeker("Park"));
 
        hh.addJob("Google Job");
        hh.addJob("Apple Job");
    }
 
}
 
cs

















예제2.




Subject.java
1
2
3
4
5
6
7
8
9
 
package observer2;
 
public interface Observer {
    public void update();
 
    public void setSubject(Subject sub);
}
 
cs
 



Observer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
 
package observer2;
 
public interface Subject {
    public void register(Observer obj);
 
    public void unregister(Observer obj);
 
    public void notifyObservers();
 
    public Object getUpdate(Observer obj);
}
 
cs
 



MyTopic.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 
package observer2;
 
import java.util.ArrayList;
import java.util.List;
 
public class MyTopic implements Subject {
 
    private List<Observer> observers;
    private String msg;
    private boolean isChanged;
    private final Object MUTEX = new Object();
 
    public MyTopic() {
        this.observers = new ArrayList<>();
    }
 
    public void register(Observer obj) {
        if (obj == null)
            throw new NullPointerException("Null Observer");
        synchronized (MUTEX) {
            if (!observers.contains(obj))
                observers.add(obj);
        }
    }
 
    public void unregister(Observer obj) {
        synchronized (MUTEX) {
            observers.remove(obj);
        }
    }
 
    public void notifyObservers() {
        List<Observer> observersLocal = null;
        synchronized (MUTEX) {
            if (!isChanged)
                return;
            observersLocal = new ArrayList<>(this.observers);
            this.isChanged = false;
        }
 
        for (Observer obj : observersLocal) {
            obj.update();
        }
    }
 
    public Object getUpdate(Observer obj) {
        return this.msg;
    }
 
    public void postMessage(String msg) {
        System.out.println("Message Posted to Topic : " + msg);
        this.msg = msg;
        this.isChanged = true;
        notifyObservers();
    }
 
}
 
cs
 


MyTopicSubscriber.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
package observer2;
 
public class MyTopicSubscriber implements Observer {
 
    private String name;
    private Subject topic;
 
    public MyTopicSubscriber(String name) {
        this.name = name;
    }
 
    public void update() {
        String msg = (String) topic.getUpdate(this);
 
        if (msg == null) {
            System.out.println(name + ":: No New Message");
        } else {
            System.out.println(name + ":: Consuming message::" + msg);
        }
    }
 
    public void setSubject(Subject sub) {
        this.topic = sub;
    }
 
}
 
cs
 



ObserverMain.java 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 
package observer2;
 
public class ObserverMain {
 
    public static void main(String[] args) {
        MyTopic topic = new MyTopic();
 
        Observer obj1 = new MyTopicSubscriber("Obj1");
        Observer obj2 = new MyTopicSubscriber("Obj2");
        Observer obj3 = new MyTopicSubscriber("Obj3");
 
        topic.register(obj1);
        topic.register(obj2);
        topic.register(obj3);
 
        obj1.setSubject(topic);
        obj2.setSubject(topic);
        obj3.setSubject(topic);
 
        obj1.update();
 
        topic.postMessage("New Message");
    }
 
}
 
cs












다른 카테고리의 글 목록

CSE/Design Pattern 카테고리의 포스트를 톺아봅니다
조회수 확인

Pattern #15  중재자 패턴




 관련되는 객체 사이에 레퍼런스를 피하는데 사용




 패턴 요약 

  - 중간 행위를 찾아 별도의 클래스에 두게 함

  - 다른 객체의 존재를 모르는 상태에서도 메시지를 주고 받을 수 있음



 

 동기

  

  당신은 자판기 제어 프로그램 개발을 주력으로 하는 회사에 취직하였다. 당신에게 주어진 일은 기존 자판기 프로그램 개발의

생산성을 저하시키는 문제점을 찾아내고, 이에 대한 해결책을 제시하는 작업이다.

 

 








 






문제점

  - 부품 객체들이 서로 강하게 연결되어 있음.

   * 각 부품 객체들이 서로 필요한 객체들을 참조하고 있다.


 



 - 한 부품의 class가 변겨오딘다면 연관된 class들의 수정이 필요하다.

 - 자판기 제어프로그램의 제어흐름이 각 부품 class마다 흩어져 있어서, 새로운 부품이 추가되었을 때 이를 위한 코드 변경이 어렵다.



해결방안

  - 부품 객체들 간의 연결을 느슨하게 만들어야 한다.

  - 각 부품 객체들간의 상호작용을 도맡아 처리하는 객체를 둔다.




 





의도

  - 여러 객체들 간으 ㅣ상호작용 자체를 encapsulation하는 객체를 정의한다.

  - 객체들끼리 직접 참조하는 것을 피함으로써 객체들 간의 연결 강도를 줄인다.

  - 객체들과 독립적으로 상호작용을 변경할 수 있다.


적용범위

  - 객체들간의 상호작용이 복잡해서 서로간의 의존관계가 구조화 되어있지 않고 이해하기 어려울 때

  - 하나의 객체가 많은 다른 객체들을 참조하고 있어 이것을 재사용하기 어려울 때

  - 여러 class에 분산되어 있는 행위를 많은 subclassing 없이 재구성해야 할 때















예제.



Colleague.java

 

1
2
3
4
5
6
7
8
package mediator;
 
public abstract class Colleague {
    IMediator mediator;
 
    public abstract void doSomething();
}
 
cs




IMediator.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
 
package mediator;
 
public interface IMediator {
    public void fight();
 
    public void talk();
 
    public void registerA(ColleagueA a);
 
    public void registerB(ColleagueB b);
}
 
cs

 





ColleagueA.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
package mediator;
 
public class ColleagueA extends Colleague {
 
    public ColleagueA(IMediator mediator) {
        this.mediator = mediator;
    }
 
    public void doSomething() {
        this.mediator.talk();
        this.mediator.registerA(this);
    }
 
}
 
cs

 



ColleagueB.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
package mediator;
 
public class ColleagueB extends Colleague {
 
    public ColleagueB(IMediator mediator) {
        this.mediator = mediator;
        this.mediator.registerB(this);
    }
    
    public void doSomething() {
        this.mediator.fight();
    }
 
}
 
cs

 




ConcreteMediator.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
package mediator;
 
public class ConcreteMediator implements IMediator {
 
    ColleagueA talk;
    ColleagueB fight;
 
    public void fight() {
        System.out.println("Mediator is fighting");
    }
 
    public void talk() {
        System.out.println("Mediator is talking");
    }
 
    public void registerA(ColleagueA a) {
        talk = a;
    }
 
    public void registerB(ColleagueB b) {
        fight = b;
    }
 
}
 
cs

 




MediatorMain.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
package mediator;
 
public class MediatorMain {
    public static void main(String[] args) {
        IMediator mediator = new ConcreteMediator();
 
        ColleagueA talkColleague = new ColleagueA(mediator);
        ColleagueB fightColleague = new ColleagueB(mediator);
 
        talkColleague.doSomething();
        fightColleague.doSomething();
    }
}
 
cs

 

















다른 카테고리의 글 목록

CSE/Design Pattern 카테고리의 포스트를 톺아봅니다
조회수 확인

Pattern #14  반복자 패턴





 자세한 표현방법을 나타내지 않고 객체집합의 요소들을 순차적으로 접근하는데 사용







 패턴 요약 
  - 반복을 집합의 요소를 포인트하는 객체 안에 캡슐화 함
  - 리스트 객체와 방문하는 프로세스 사이의 결합을 줄임


 
 동기
  

  당신은 기업정보 관리시스템 개발 프로젝트의 책임자로 선발되었다. 이 프로그램 은 크게 user interface, application logic, data management 세 파트로 나뉘는데 이들은 병렬적으로 개발된다. 개발 에 있어 한 가지 문제점 은 application logic 파트와 data management 파트와의 연결 부분이다 . 즉 , data management 파트에서 개발을 맡고 있는 data structure class의 interface 가 확정되지 않은 상황에서 이를 이용한 application logic 구현은 어려운 형편이다. 팀장으로서 이런 상황에서 제시할 당신의 해결책은? 

 




 








 해결방안1: Data Structure Interface를 단일화
 - 외부에서 사용하는 DS class의 interface를 통일











 해결방안1 문제점
 - 다른 DS class로 교체될 때마다 Client code 수정 필요
 - 자료구조 검색과 상관없더라도 DS class의 interface가 수정될 때 마다 client code 재 컴파일 필요
 - 자료구조 관리를 위한 기존의 interface와 Client를 위해 단일화된 검색 interface, 두가지가 하나의 DS class로 구현을 하기 때문에 class의 크기가 커지고, 더욱 복잡해진다.





 해결방안2: 자료구조 검색을 자료구조 Class와 분리
 - Data Structure class에서 Client가 필요로 하는 자료구조 검색부분을 분리 -Interator class
 - 각 DS class마다 해당 자료구조의 검색을 위한 Iterator 객체 생성 함수를 구현 - CreateIterator()





 






 의도
 - 동일한 자료형의 객체가 여러 개 모여 있을 때 각 객체들을 순차적으로 접근할 수 있는 방법을 제공한다.
 - 검색 기능을 자료구조와 분리시켜 객체로 만든다.



 별칭
 - Cursor



 적용범위
 - 여러 객체들을 모아 관리하는 Aggregate 객체에 대해 내부 구조나 구현에 신경쓰지 않고 저장된객체들을 순차적으로 접근하고자할 때
 - 동일한 Aggregate 객체에 대해 여러 개의 검색 instance를 가지고자 할 때
  * Iterator *iter1 = ds->CreateInstance();  순방향 검색에 사용
  * Iterator *iter2 = ds->CreateInstance();  역방향 검색에 사용
 - 서로 다른 구조를 가긴 Aggregate 객체에 대해 저장된 객체들을 접근하기 위한 interface를 단일화하고자 할 때



 결과
 - ConcreteIterator 구현에 따라 다양한 형태의 검색을 지원 할 수 있다.
 - 반복자는 Aggregate interface를 단순화시킨다.
 





IIterator.java

 

1
2
3
4
5
6
7
8
9
 
package iterator;
 
public interface IIterator {
    public boolean hasNext();
 
    public Object next();
}
 
cs





 IContainer.java

 

1
2
3
4
5
6
7
 
package iterator;
 
public interface IContainer {
    public IIterator createIterator();
}
 
cs




RecordCollection.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 
package iterator;
 
public class RecordCollection implements IContainer {
 
    private String recordArray[] = { "first""second""third""fourth",
            "fifth" };
 
    public IIterator createIterator() {
        RecordIterator iterator = new RecordIterator();
        return iterator;
    }
 
    private class RecordIterator implements IIterator {
        private int index;
 
        public boolean hasNext() {
            if (index < recordArray.length) {
                return true;
            } else {
                return false;
            }
        }
 
        public Object next() {
            if (this.hasNext()) {
                return recordArray[index++];
            } else {
 
                return null;
            }
        }
 
    }
 
}
 
cs

 





IteratorMain.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
 
package iterator;
 
public class IteratorMain {
    public static void main(String[] args) {
        RecordCollection recordCollection = new RecordCollection();
        IIterator iter = recordCollection.createIterator();
 
        while (iter.hasNext()) {
            System.out.println(iter.next());
        }
    }
}
cs


 







  


다른 카테고리의 글 목록

CSE/Design Pattern 카테고리의 포스트를 톺아봅니다
조회수 확인

Pattern #13  인터프리터 패턴




 간단한 언어의 문법을 정의하고 해석하는데 사용




 패턴 요약 

  - 문법을 재귀적으로 표현

  - 집합 객체에게 그 해석을 패스



 

 동기

  

  당신이 새롭게 맡은 일은 전략게임의 인공지능 부분에 대한 설계와 개발 작업이다. 게임의 인공지능은 수 많은 규칙(rule)들에 그 기반을 두고 있는데, 이러한 규칙들을 분석하고 실행하기 위해서는 논리식을 표현하고 계산할 수 있어야 한다. 변수와 논리곱(and), 논리합(or,) 부정(not), 상수(true, false)로 구성된 기본적인 predicate first logic을 표현하고 계산할 수 있는 논리 시스템을 설계하라. 



 BNF로 문법 표현










 


 BNF Syntax를 클래스다이어그램으로 표현
   - 일반적으로 BNF로 표현된 Syntax의 언어를 분석하면 part-whole 형태의 Tree 구조가 된다. 


 













 의도
 - 특정 언어가 주어졌을 때, 이 언어로 작성된 문장을 해석할 수 있도록, 언어의 문법을 표현하고 해석기능을 지원한다.
 - 간단한 문법에 대한 Interpreter 설계



 적용범위
 - 문법이 간단할 때 => 복잡한 문법의 경우 이를 표현하기 위한 class hierarchy가 비대해지고 관리하기 어려워진다.
 - 성능이 중요한 문제가 되지 않을 때 => Interpreter pattern은 특정 언어로 기술된 문장을 분석해서 객체들의 Tree 구조를 생성하기 때문에 속도나 효율은 떨어질 수 있다.



 결과
 - 문법을 변경하고 확장하기 좋음
 - 문법을 구현하기 쉬움 => Syntax tree의 각 노드들에 표현된 클래스들은 비슷한 구현을 가진다.
 - 복잡한 문법은 유지하기 어려움 => 문법 규칙이 많아질 수록 클래스 수도 따라 증가하여 관리하기 어려워진다.




예제.


Expression.java
1
2
3
4
5
6
7
 
package interpreter;
 
public interface Expression {
    public String interpret(InterpreterContext ic);
}
 
cs

 



InterpreterContext.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
 
package interpreter;
 
public class InterpreterContext {
    public String getBinaryFormat(int i) {
        return Integer.toBinaryString(i);
    }
 
    public String getHexadecimalFormat(int i) {
        return Integer.toHexString(i);
    }
}
 
cs

 



 IntToBinaryExpression.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
package interpreter;
 
public class IntToBinaryExpression implements Expression {
 
    private int i;
 
    public IntToBinaryExpression(int i) {
        this.i = i;
    }
 
    public String interpret(InterpreterContext ic) {
        return ic.getBinaryFormat(this.i);
    }
 
}
 
cs




IntToHexExpression.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
package interpreter;
 
public class IntToHexExpression implements Expression {
 
    private int i;
 
    public IntToHexExpression(int i) {
        this.i = i;
    }
 
    public String interpret(InterpreterContext ic) {
        return ic.getHexadecimalFormat(i);
    }
 
}
 
cs




InterpreterMain.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 
package interpreter;
 
public class InterpreterMain {
    public InterpreterContext ic;
 
    public InterpreterMain(InterpreterContext i) {
        this.ic = i;
    }
 
    public String interpret(String str) {
        Expression exp = null;
 
        if (str.contains("Hexdecimal")) {
            exp = new IntToHexExpression(Integer.parseInt(str.substring(0,
                    str.indexOf(" "))));
        } else if (str.contains("Binary")) {
            exp = new IntToBinaryExpression(Integer.parseInt(str.substring(0,
                    str.indexOf(" "))));
        } else {
            return str;
        }
 
        return exp.interpret(ic);
    }
 
    public static void main(String[] args) {
        String str1 = "28 in Binary";
        String str2 = "28 in Hexadecimal";
 
        InterpreterMain ec = new InterpreterMain(new InterpreterContext());
        System.out.println(str1 + "= " + ec.interpret(str1));
        System.out.println(str2 + "= " + ec.interpret(str2));
 
    }
}
 
cs








 









 


다른 카테고리의 글 목록

CSE/Design Pattern 카테고리의 포스트를 톺아봅니다