본문 바로가기
정보처리기사/필기

[정보처리기사 필기 요약] 디자인 패턴(3) - 행위패턴

by 채연2 2021. 3. 2.

* 행위패턴 (Behavioral Pattern) : 객체 간 기능 분배하는 일과 같은 로직 수행에 주로 이용하여 객체 간 연동에 대한 유형 제공

 

종류 개념
Template method - 상위 클래스에서 처리 흐름 정하고 하위 클래스에서 구체적인 내용 재정의
Interpreter - 간단한 언어 문법 정의하는 방법과 그 언어로 문장 구성하는 방법, 문장 해석하는 방법 제시
Iterator - 집합 객체 요소들 내부 표현 방식 공개 않고 순차적으로 접근하는 구조 제공
Command - 요청 자체를 객체화(캡슐화)하고 매개변수(파라미터) 추가하여 여러 가지 요구사항 추가 가능(로그기록, 작업 취소 지원)
Chain of Resposibility - 요청 처리 가능한 기회를 하나 이상 객체에 부여함으로써 객체 간 결합도 없애려 함
State - 상태 일반적인 데이터 변수로 두지 않고 객체로 만들어 그 상태에 따른 행동들 분리
Strategy - 상황에 따라 알고리즘 변경할 필요 있을 때, 각 알고리즘 클래스들을 공통된 인터페이스에 맞게 구현하여 다형성 활용
Mediator - 중재자 통해 한 집합에 속해있는 객체들 상호작용 캡슐화
Memento - 어떤 시점에서의 객체 상태 저장해 두었다가 필요 시 객체 그 시점 상태로 되돌림
Visitor - 데이터 구조 안을 돌아다니는 주체인 '방문자'를 나타내는 클래스 준비해서 그 클래스에게 처리를 맡김으로서 기능 추가 시 유연성 제공
Observer - 한 객체 상태가 바뀌면 그 객체에 의존하는 다른 객체들에게 통지되고 필요 시 자동으로 내용 갱신

 

 

* Template method Pattern

- 구현 별로 달라질 수 있는 행동(메서드)들은 구현 클래스에서 선언 후 호출하는 방식으로 사용

//Template method
//소스코드의 중복을 줄이기 위해 하위 클래스에서 빈번하고 공통적으로 나타나는 부분에 대해서 별도의 추상 클래스를 정의해서 사용
//상위 클래스(여기선 추상 클래스)에게 공통적인 로직은 템플릿 메서드를 두고,
//구체 클래스 스타일에 맞게 구현을 강제하기 위해 추상 메서드를 사용하고,
//Hook메서드(일반 메서드)를 두는 패턴
public abstract class HouseTemplate {
    public final void buildHouse() {
        buildFoundation();
        buildPillars();
        buildWalls();
        buildWindows();
        System.out.println("House is built");
    }

    private void buildWindows() {
        System.out.println("Building Glass Windows");
    }

    public abstract void buildWalls();
    public abstract void buildPillars();

    private void buildFoundation(){
        System.out.println("Building foundation with cement,iron rods and sand");
    }
}

//concrete class
public class GlassHouse extends HouseTemplate {
    @Override
    public void buildWalls() {
        System.out.println("Building Glass Walls");
    }

    @Override
    public void buildPillars() {
        System.out.println("Building Pillars with glass coating");
    }
}

public class WoodenHouse extends HouseTemplate {
    @Override
    public void buildWalls() {
        System.out.println("Building Wooden Walls");
    }

    @Override
    public void buildPillars() {
        System.out.println("Building Pillars with Wood coating");
    }
}

public class HousingClient {
    public static void main(String[] args) {
        HouseTemplate houseType = new WoodenHouse();

        houseType.buildHouse();

        System.out.println();
        System.out.println("***********");
        System.out.println();

        houseType = new GlassHouse();
        houseType.buildHouse();
    }
}

 

 

* Interpreter Pattern

- 일련의 규칙으로 정의된 언어를 해석

//Expression interface(혹은 abstract class)를 생성하고 Expression interface 구현하는 구상 클래스를 생성
//interpreterPatternDemo에서 규칙을 생성하고 main 함수 안에 정의된 언어   John  male  , Married Julie를 해석
public interface Expression {
    public boolean interpret(String context);
}

public class AndExpression implements Expression {
   private Expression expr1 = null;
   private Expression expr2 = null;

   public AndExpression(Expression expr1, Expression expr2) { 
      this.expr1 = expr1;
      this.expr2 = expr2;
   }

   @Override
   public boolean interpret(String context) {		
      return expr1.interpret(context) && expr2.interpret(context);
   }
}

public class OrExpression implements Expression {
   private Expression expr1 = null;
   private Expression expr2 = null;

   public OrExpression(Expression expr1, Expression expr2) {
      this.expr1 = expr1;
      this.expr2 = expr2;
   }

   @Override
   public boolean interpret(String context) {		
      return expr1.interpret(context) || expr2.interpret(context);
   }
}

public class TerminalExpression implements Expression {
   private String data;

   public TerminalExpression(String data){
      this.data = data; 
   }

   @Override
   public boolean interpret(String context) {
   
      if(context.contains(data)){
         return true;
      }
      return false;
   }
}

public class InterpreterPatternDemo {
   //Rule: Robert or John are male
   public static Expression getMaleExpression(){
      Expression robert = new TerminalExpression("Robert");
      Expression john = new TerminalExpression("John");
      return new OrExpression(robert, john);
   }

   //Rule: Julie is a married women
   public static Expression getMarriedWomanExpression(){
      Expression julie = new TerminalExpression("Julie");
      Expression married = new TerminalExpression("Married");
      return new AndExpression(julie, married);		
   }

   public static void main(String[] args) {
      Expression isMale = getMaleExpression();
      Expression isMarriedWoman = getMarriedWomanExpression();

      System.out.println("John is male? " + isMale.interpret("John male"));
      System.out.println("Julie is a married women? " + isMarriedWoman.interpret("Married Julie"));
   }
}

 

 

* Iterator Pattern

서로 다른 구조를 가지고 있는 저장 객체에 대해서  접근하기 위해서  interface를 통일시키고 싶을 때 주로  사용

//goat는 자바에서 제공하는 hashMap의 Iterator를 (내부에 Iterator<E> 인터페이스를 구현) 
//SheapIterator는 Iterator<E> 인터페이스를 구현하여 만든 Iterator
public interface Animal {
    public void eat();
    public void sleep();
    public void sound();
}

public class Sheep implements Animal {
    @Override
    public void eat() {
        System.out.println("길쭉한 풀 뜯어먹음");
    }
 
    @Override
    public void sleep() {
        System.out.println("앉아서 잠");
    }
 
    @Override
    public void sound() {
        System.out.println("메에에");
    }
}

public class Goat implements Animal {
    @Override
    public void eat() {
        System.out.println("짧은 풀 뜯어먹음");
    }
 
    @Override
    public void sleep() {
        System.out.println("엎드려서 잠");
    }
 
    @Override
    public void sound() {
        System.out.println("음메에에");
    }
}

public class Goatherd {
    public static final int MAX_GOATS = 100;
    private int goatNum = 0;
    public static final HashMap<Integer, Goat> GOATS = new HashMap<>();
 
    public Goatherd() {
        super();
        int i;
 
        for (i = 0; i < 30; ++i) {
            GOATS.put(i, new Goat());
 
        }
 
        goatNum = i;
    }
 
    public void addGoat() {
        if (GOATS.size() <= MAX_GOATS) GOATS.put(goatNum++, new Goat());
    }
 
    public void removeGoat() {
        GOATS.remove(goatNum--);
    }
    
    public Iterator<Integer> createIterator() {
        return GOATS.keySet().iterator();
    }
}

public class SheepIterator implements Iterator<Sheep> {
    private Sheep[] sheeps;
    int position = 0;
 
    public SheepIterator(Sheep[] sheeps) {
        super();
        this.sheeps = sheeps;
 
    }
 
    @Override
    public boolean hasNext() {
        if (position >= sheeps.length || sheeps[position] == null) {
            return false;
 
        } else {
            return true;
        }
    }
 
    @Override
    public Sheep next() {
        Sheep tempSheep = sheeps[position];
        position++;
        return tempSheep;
    }
}

public class Client {
    public static void main(String[] args) {

        Goatherd goatherd = new Goatherd();
        Shepherd shepherd = new Shepherd();

        Iterator<Integer> goatIter = goatherd.createIterator();
        Iterator<Sheep> sheepIter = shepherd.createIterator();

        while(goatIter.hasNext()) {
            Goat goat = goatherd.GOATS.get(goatIter.next());
            goat.sound();
        }

        while(sheepIter.hasNext()) {
            Sheep sheep = sheepIter.next();
            sheep.sound();
        }
    }
}

 

 

* Command Pattern

- 이벤트가 발생했을 때 실행될 기능이 다양하면서도 변경이 필요한 경우에 이벤트를 발생시키는 클래스를 변경하지 않고 재사용하고자 할 때 유용

- 실행될 기능을 캡슐화함으로써 기능의 실행을 요구하는 호출자(Invoker) 클래스와 실제 기능을 실행하는 수신자(Receiver) 클래스 사이의 의존성을 제거

//실행될 기능을 캡슐화하고 , 실행될 기능을 커맨드를 통해  실행하는 패턴
//기능이 실행된 후에는  Receiver에 수행된 기능에 대하여 알려줌.
public interface Command { public abstract void execute(); }

//invoker
public class Button {
    private Command theCommand;

    public Button(Command theCommand) {
        setCommand(theCommand);
    }

    public void setCommand(Command newCommand) {
        this.theCommand = newCommand;
    }

    public void pressed() {
        theCommand.execute();
    }
}

//receiver
public class Alarm {
    public void start() {
        System.out.println("Alarming");
    }
}

public class Lamp {
    public void turnOn() {
        System.out.println("Lamp On");
    }
}

//concreteCommand
public class AlarmStartCommand implements Command {
    private Alarm theAlarm;

    public AlarmStartCommand(Alarm theAlarm) {
        this.theAlarm = theAlarm;
    }

    public void execute() {
        theAlarm.start();
    }
}

public class LampOnCommand implements Command {
    private Lamp theLamp;

    public LampOnCommand(Lamp theLamp) {
        this.theLamp = theLamp;
    }

    public void execute() {
        theLamp.turnOn();
    }
}

 

 

* Chain of Resposibility Pattern

- 요청 처리가 들어오게 되면 그것을 수신하는 객체가 자신이 처리할 수 없는 경우에는 다음 객체에게 문제를 넘김으로써 최종적으로 요청 처리 가능한 객체에 의해 처리 가능토록 함

- 각각의 처리 객체는 명령 객체를 처리할 수 있는 연산의 집합이고, 체인 안의 처리 객체가 핸들 할 수 없는 명령은 다음 처리 객체로 넘겨짐. 이 작동방식은 새로운 처리 객체부터 체인의 끝까지 다시 반복

- 예) try-catch-finally : try 안에서 Exception 발생하면 catch 로 이동하여 코드 수행

//들어온 Amount에 따라 Manager->Director -> VicePresident->President 순으로 Responsibliity를 check
//Check한후 자신의 ALLOWABLE보다  크다면 다음 PurchasePower으로 책임을 넘김
abstract class PurchasePower {
    protected final double base = 500;
    protected PurchasePower successor;

    public void setSuccessor(PurchasePower successor) {
        this.successor = successor;
    }

    abstract public void processRequest(PurchaseRequest request);
}

class ManagerPower extends PurchasePower {
    private final double ALLOWABLE = 10 * base;

    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < ALLOWABLE) {
            System.out.println("Manager will approve $" + request.getAmount());
        } else if (successor != null) {
            successor.processRequest(request);
        }
    }
}

class DirectorPower extends PurchasePower {
    private final double ALLOWABLE = 20 * base;

    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < ALLOWABLE) {
            System.out.println("Director will approve $" + request.getAmount());
        } else if (successor != null) {
            successor.processRequest(request);
        }
    }
}

class VicePresidentPower extends PurchasePower {
    private final double ALLOWABLE = 40 * base;

    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < ALLOWABLE) {
            System.out.println("Vice President will approve $" + request.getAmount());
        } else if (successor != null) {
            successor.processRequest(request);
        }
    }
}

class PresidentPower extends PurchasePower {
    private final double ALLOWABLE = 60 * base;

    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < ALLOWABLE) {
            System.out.println("President will approve $" + request.getAmount());
        } else {
            System.out.println( "Your request for $" + request.getAmount() + " needs a board meeting!");
        }
    }
}

class PurchaseRequest {
    private int number;
    private double amount;
    private String purpose;

    public PurchaseRequest(int number, double amount, String purpose) {
        this.number = number;
        this.amount = amount;
        this.purpose = purpose;
    }

    public double getAmount() {
        return amount;
    }
    public void setAmount(double amt)  {
        amount = amt;
    }

    public String getPurpose() {
        return purpose;
    }
    public void setPurpose(String reason) {
        purpose = reason;
    }

    public int getNumber(){
        return number;
    }
    public void setNumber(int num) {
        number = num;
    }
}

class CheckAuthority {
    public static void main(String[] args) {
        ManagerPower manager = new ManagerPower();
        DirectorPower director = new DirectorPower();
        VicePresidentPower vp = new VicePresidentPower();
        PresidentPower president = new PresidentPower();
        manager.setSuccessor(director);
        director.setSuccessor(vp);
        vp.setSuccessor(president);

        // Press Ctrl+C to end.
        try {
            while (true) {
                System.out.println("Enter the amount to check who should approve your expenditure.");
                System.out.print(">");
                double d = Double.parseDouble(new BufferedReader(new InputStreamReader(System.in)).readLine());
                manager.processRequest(new PurchaseRequest(0, d, "General"));
           }
        } catch(Exception e) {
            System.exit(1);
        }
    }
}

 

 

* State Pattern

- 일련의 규칙에 따라 객체의 상태(State)를 변화시켜, 객체가 할 수 있는 행위 바꿈

- 상태에 따라 행동 변화하는 객체엔 모두 적용 가능

- 전략 패턴은 상속을 대체하려는 목적, 스테이트 패턴은 코드 내의 조건문들을 대체하려는 목적

public interface PowerState {
    public void powerPush();
}

public class On implements PowerState{
    public void powerPush(){
        System.out.println("power on");
    }
}
public class Off implements PowerState {
    public void powerPush(){
        System.out.println("power off");
    }
}
public class Saving implements PowerState {
    public void powerPush(){
        System.out.println("power saving");
    }
}
public class Laptop {
    private PowerState powerState;

    public Laptop(){
        this.powerState = new Off();
    }

    public void setPowerState(PowerState powerState){
        this.powerState = powerState;
    }

    public void powerPush(){
        powerState.powerPush();
    }
}
public class Client {
    public static void main(String args[]){
        Laptop laptop = new Laptop();
        On on = new On();
        Off off = new Off();
        Saving saving = new Saving();

        laptop.powerPush();
        laptop.setPowerState(on);
        laptop.powerPush();
        laptop.setPowerState(saving);
        laptop.powerPush();
        laptop.setPowerState(off);
        laptop.powerPush();
        laptop.setPowerState(on);
        laptop.powerPush();
    }
}

 

 

* Strategy Pattern

- 객체의 행위를 동적으로 바꾸고 싶은 경우 직접 행위를 수정하지 않고 전략을 바꿔주기만 함으로써 행위를 유연하게 확장하는 방법

- 즉 , 객체가 할 수 있는 행위들을 각각의 전략으로 정의, 수정이 필요한 경우 전략을 바꾸는 것만으로도 수정이 가능하도록 만드는 패턴

//Strategy Pattern 미적용
public interface Movable {
    public void move();
}

public class Train implements Movable{
    public void move(){
        System.out.println("선로를 통해 이동");
    }
}

public class Bus implements Movable{
    public void move(){
        System.out.println("도로를 통해 이동");
    }
}

public class Client {
    public static void main(String args[]){
        Movable train = new Train();
        Movable bus = new Bus();

        train.move();
        bus.move();
    }
}

//기차는 선로 따라 이동, 버스는 도로 따라 이동. 시간이 흘러 선로 따라 움직이는 버스가 개발되었다고 가정
public void move(){
    System.out.println("선로를 따라 이동");
}

//위와 같이 수정하는 방식은 OCP에 위배
//위와 같은 문제 해결하기 위해 Strategy Pattern 사용 가능
//Strategy Pattern 사용
//전략 정의
public interface MovableStrategy {
    public void move();
}

public class LoadStrategy implements MovableStrategy {
    @Override
    public void move() {
        System.out.println("도로를 통해 이동");
    }
}

public class RailLoadStrategy implements MovableStrategy {
    @Override
    public void move() {
        System.out.println("선로를 통해 이동");
    }
}

//운송수단 선언
public class Moving {
    private MovableStrategy movableStrategy;

    public void move() {
        movableStrategy.move();
    }

    public void setMovableStrategy(MovableStrategy movableStrategy) {
        this.movableStrategy = movableStrategy;
    }
}
public class Bus extends Moving {}
public class Train extends Moving {}

//result
public class Client {
    public static void main(String[] args) {
        Moving train = new Train();
        Moving bus = new Bus();

        train.setMovableStrategy(new RailLoadStrategy());
        bus.setMovableStrategy(new LoadStrategy());

        train.move();
        bus.move();

        /** rail load bus development*/
        bus.setMovableStrategy(new RailLoadStrategy());
        bus.move();
    }
}

 

 

* Mediator Pattern

- 클래스 간의 상호작용을 하나의 클래스에 위임하여 처리하는 패턴

- M:N의 관계에서 M:1의 관계로 복잡도를 떨어뜨려 유지보수 및 확장성에 유리

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

//ConcreteColleague클래스는 Colleague(동료) interface를 구현하고 있는 N개의 객체
//ConcreteCollegue 클래스 간 데이터 전달을 위하여 Mediator를 이용
//Mediator에  ConcreteColleage를 등록하고 연결다리로 사용
public class ChatUser {
    private ChatMediator mediator;
    private String name;

    public ChatUser(ChatMediator mediator, String name) {
        this.mediator = mediator;
        this.name = name;
    }

    public void send(String msg) {
        System.out.println(name + " Sending Message = " + msg);
        mediator.sendMessage(msg, this);
    }

    public void receive(String msg) {
        System.out.println(name + " Message received : " + msg);
    }
}

public class ChatMediator {
    private List<ChatUser> users = new ArrayList<>();

    public void sendMessage(String msg, ChatUser user) {
        users.stream()
                .filter(u -> u != user)
                .forEach(u -> u.receive(msg));
    }

    public ChatMediator addUser(ChatUser user) {
        users.add(user);
        return this;
    }
}

public class MediatorTest {
    public static void main(String[] args) {
        ChatMediator mediator = new ChatMediator();

        ChatUser john = new ChatUser(mediator,"John");

        mediator.addUser(new ChatUser(mediator,"Alice"))
                .addUser(new ChatUser(mediator,"Bob"))
                .addUser(john);

        john.send("Hi every one!");
    }
}

//result
John: Sending Message= Hi everyone!
Alice: Message received: Hi everyone!
Bob: Message received: Hi everyone!

 

 

* Memento Pattern

- 3개의 액터 클래스를 사용. 메멘토에는 복원할 개체의 상태가 포함

  • Originator : 현재 State를 가지고, Memento 객체와 Memento 객체 상태를 얻게 합니다.
  • Memento : State를 가지고 있는 인스턴스입니다.
  • CareTaker : Memento를 순서대로 저장합니다.
//Originator는 Memento 인스턴스를 생성하고 또다시 또 그 객체를 반환하는 역할.
//Craker는  Memento객체를 List에 순서대로 save
public class Memento {
   private String state;

   public Memento(String state){
      this.state = state;
   }

   public String getState(){
      return state;
   }	
}

public class Originator {
   private String state;

   public void setState(String state){
      this.state = state;
   }

   public String getState(){
      return state;
   }

   public Memento saveStateToMemento(){
      return new Memento(state);
   }

   public void getStateFromMemento(Memento memento){
      state = memento.getState();
   }
}

public class CareTaker {
   private List<Memento> mementoList = new ArrayList<Memento>();

   public void add(Memento state){
      mementoList.add(state);
   }

   public Memento get(int index){
      return mementoList.get(index);
   }
}

public class MementoPatternDemo {
   public static void main(String[] args) {
      Originator originator = new Originator();
      CareTaker careTaker = new CareTaker();
      originator.setState("State #1");
      originator.setState("State #2");
      careTaker.add(originator.saveStateToMemento());
      originator.setState("State #3");
      careTaker.add(originator.saveStateToMemento());
      originator.setState("State #4");

      System.out.println("Current State: " + originator.getState());		
      originator.getStateFromMemento(careTaker.get(0));
      System.out.println("First saved State: " + originator.getState());
      originator.getStateFromMemento(careTaker.get(1));
      System.out.println("Second saved State: " + originator.getState());
   }
}

//result
Current State: State #4
First saved State: State #2
Second saved State: State #3

 

 

* Visitor Pattern

- 데이터 구조와 연산을 분리하여 데이터 구조의 원소들을  변경하지 않고 새로운 연산을 추가할 수 있는  패턴. 새로운 연산을 추가하려면 새로운  방문자를 추가하기만 하면 됨

public interface Element {
    public void accept(Visitor v);
}

public abstract class Entry implements Element {
    String name;
    public Entry(String name) {
        this.name = name;
    }

    public abstract void add(Entry entry);
}

public class Directory extends Entry {
    ArrayList<Entry> directory = new ArrayList();

    public Directory(String name) {
        super(name);
    }

    public void add(Entry entry) {
        directory.add(entry);
    }

    public void accept(Visitor v) {
        v.visit(this);
    }
}

public class File extends Entry {
    public File(String name) {
        super(name);
    }

    public void add(Entry entry) {

    }

    public void accept(Visitor v) {
        v.visit(this);
    }
}

public abstract class Visitor {
    public abstract void visit(File file);
    public abstract void visit(Directory directory);
}

public class ViewVisitor extends Visitor {
    private String Path = "";

    public void visit(File file) {
        System.out.println(Path + "/" + file.name);
    }

    public void visit(Directory dic) {
        Path = Path + "/" + dic.name;
        System.out.println(Path);
        for (int i = 0; i < dic.directory.size(); i++) {
            dic.directory.get(i).accept(this);
        }
    }
}

public class Client {
    public static void main(String[] args){
        Directory root = new Directory("root");
        Directory bin = new Directory("bin");
        Directory Lkt = new Directory("Lkt");
        File file1 = new File("file1");
        File file2 = new File("file2");
        File file3 = new File("file3");
        File file4 = new File("file4");

        root.add(file1);
        bin.add(file2);
        bin.add(file3);
        Lkt.add(file4);
        root.add(Lkt);
        root.add(bin);

        root.accept(new ViewVisitor());    //경로 출력
    }
}

//result
/root
/root/file1
/root/Lkt
/root/Lkt/file4
/root/Lkt/bin
/root/Lkt/bin/file2
/root/Lkt/bin/file3

 

 

* Observer Pattern

- 한 객체의 상태 변화에 따라 다른 객체의 상태도 연동되도록 일대다 객체 의존 관계를 구성하는 패턴

- PUSH : 주제 객체가 구독 객체에게 상태를 보내는 방식

- PULL : 구독 객체가 주제 객체에게서 상태를 가져가는(요청하는) 방식

- 데이터의 변경이 발생하였을 때 상대 클래스나 객체에 의존하지 않으면서 데이터 변경을 통보하고자 할 때 사용

//Subject클래스 상속하는 DashBoard에 Observer 등록하고 setMessage메서드 호출하면 subscriber에게 이벤트가 전달
public interface Subject {
	public void add(Observer observer);
	public void remove(Observer observer);
	public void notifyObservers();
	public void notifyObserver(Observer observer);
}

public class DashBoard implements Subject {
    private List<Observer> displays;
    private String content;

    public DashBoard() {
        System.out.println("DashBoard(Display Subject)Create");
        displays = new LinkedList<Observer>();
    }

    @Override
    public void add(Observer observer) {
        displays.add(observer);
    }

    @Override
    public void remove(Observer observer) {
        if (displays.contains(observer)) {
            displays.remove(observer);
        }
    }

    @Override
    public void notifyObservers() {
        for (Observer display : displays) {
            display.update(content);
        }
    }

	//전달받은 특정 observer 에게만 update
	@Override
    public void notifyObserver(Observer observer) {
        observer.update(content);
    }

    public void setMessage(String content) {
        this.content = content;
        notifyObservers();
    }
}

public interface Observer {
	public void update(String content);
}

//Subscriber 클래스에는 subject를 pull 하는 메서드를 호출
public class Subscriber implements Observer {
    private String content;
    private Subject subject;

    public Subscriber(Subject subject) {
        this.subject = subject;
        subject.add(this);
    }

    public void pullContent() {
        System.out.println("Pull Contents is");
        subject.notifyObserver(this);
    }

    @Override
    public void update(String content) {
        this.content = content;
        display();
    }

    private void display() {
        System.out.println("subscriber 1");
        System.out.println("content : " + content);
        System.out.println("\n");
    }
}

public class Subscriber2 implements Observer {
    Subject subject;
    private String content;

    public Subscriber2(Subject subject) {
        subject.add(this);
    }

    @Override
    public void update(String content) {
        this.content = content;
        display();
    }

    private void display() {
        System.out.println("subscriber 2");
        System.out.println("content : " + content);
        System.out.println("\n");
    }
}

public class Messenger {
	public static void main(String[] args) {
		DashBoard dashBoard = new DashBoard(); //Subject class create
        Subscriber subscriber = new Subscriber(dashBoard);
        Subscriber2 subscriber2 = new Subscriber2(dashBoard);

        dashBoard.setMessage("some event"); //Subject new message send

        subscriber.pullContent();
        subscriber2.pullContent();
    }
}

//result
DashBoard(Display Subject)Create

subscriber 1
content : some event

subscriber 2
content : some event

Pull Contents is
subscriber 1
content : some event

Pull Contents is
subscriber 2
content : some event

 

 

참고 : beomseok95.tistory.com/category/DesignPattern

320x100

댓글