아무거나

[Design Pattern] Chain of Responsibility Pattern 본문

Java & Kotlin/Java

[Design Pattern] Chain of Responsibility Pattern

전봉근 2020. 1. 4. 03:59
반응형

책임 사슬 패턴(Chain of Responsibility Pattern)

다양한 처리 방식을 유연하게 연결할 수 있다.

 

 

Handler가 다음번에 처리할 객체들을 가지고 있어가지고 자기가 가지고 있는 프로세스가 실패할 경우 다음번 객체(=ConcreteHandler ..)로 넘겨주는 설계방식

책임 사슬 패턴 예시 - 1

사칙 연산을 하는 프로그램

Calculator 클래스 선언
[Calculator.java]

package com.bkjeon.chain_of_responsibility;

public abstract class Calculator {

    private Calculator nextCalculator;

    public void setNextCalculator(Calculator nextCalculator) {
        this.nextCalculator = nextCalculator;
    }

    public boolean process(Request request) {
        if (operator(request)) {
            return true;
        } else {
            if (nextCalculator != null) {
                return nextCalculator.process(request);
            }
        }
        return false;
    }

    abstract protected boolean operator(Request request);
}

[Request.java]

package com.bkjeon.chain_of_responsibility;

public class Request {

    int a,b;
    String operator;

    public Request(int a, int b, String operator) {
        super();
        this.a = a;
        this.b = b;
        this.operator = operator;
    }

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public int getB() {
        return b;
    }

    public void setB(int b) {
        this.b = b;
    }

    public String getOperator() {
        return operator;
    }

    public void setOperator(String operator) {
        this.operator = operator;
    }
}

[PlusCalculator.java]

package com.bkjeon.chain_of_responsibility;

public class PlusCalculator extends Calculator {

    @Override
    protected boolean operator(Request request) {
        if (request.getOperator().equals("+")) {
            int a = request.getA();
            int b = request.getB();
            int result = a + b;
            System.out.println(a + "+" + b + "=" + result);
        }
        return false;
    }

}

[SubCalculator.java]

package com.bkjeon.chain_of_responsibility;

public class SubCalculator extends Calculator {
    @Override
    protected boolean operator(Request request) {
        if (request.getOperator().equals("-")) {
            int a = request.getA();
            int b = request.getB();
            int result = a - b;
            System.out.println(a + "-" + b + "=" + result);
        }
        return false;
    }
}

[Main.java]

package com.bkjeon.chain_of_responsibility;

public class Main {

    public static void main(String[] args) {
        Calculator plus = new PlusCalculator();
        Calculator sub = new SubCalculator();
        plus.setNextCalculator(sub);

        Request request1 = new Request(1, 2, "+");
        Request request2 = new Request(10, 2, "-");
        plus.process(request1);
        plus.process(request2);
    }

}

[실행결과]

1+2=3
10-2=8

PlusCalculator 에서 처리를 하되 처리를 못할 경우에는 setNextCalculator에 넘겨준 다음 동작인 SubCalculator 처리를 한다.

만약 나중 실행인 SubCalculator 연산이 먼저 되게 하려면 아래와 같이 Calculator를 수정하자.
[Calculator.java]

package com.bkjeon.chain_of_responsibility;

public abstract class Calculator {

//    private Calculator nextCalculator;
    private Calculator preCalculator;

    public void setNextCalculator(Calculator nextCalculator) {
//        this.nextCalculator = nextCalculator;
        this.preCalculator = nextCalculator;
    }

    public boolean process(Request request) {
        // 처음 프로세스 실행 후 문제가 생기면 다음 프로세스 실행
//        if (operator(request)) {
//            return true;
//        } else {
//            if (nextCalculator != null) {
//                return nextCalculator.process(request);
//            }
//        }
//        return false;

        // 먼저 다른 프로세스에 넘긴 다음에 다른 프로세스가 처리를 못하면 처음의 프로세스가 처리를 한다.
        if (preCalculator != null) {
            if (preCalculator.process(request)) {
                return true;
            }
        }
        return operator(request);
    }

    abstract protected boolean operator(Request request);
}

책임 사슬 패턴 예시 - 2

게임에서 공격을 받고 처리하는 부분을 구현해보자.

공격 클래스를 구현
[Attack.java]

package com.bkjeon.chain_of_responsibility.example2;

public class Attack {

    private int amount;

    public Attack(int amount) {
        this.amount = amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }

    public int getAmount() {
        return amount;
    }
}

방어 기능에 대한 인터페이스를 구현
[Defense.java]

package com.bkjeon.chain_of_responsibility.example2;

public interface Defense {

    public void defense(Attack attack);

}

갑옷에 관련된 클래스를 구현
[Armor.java]

package com.bkjeon.chain_of_responsibility.example2;

public class Armor implements Defense {

    private Defense nextDefense;
    private int def;

    public Armor() {

    }

    public Armor(int def) {
        this.def = def;
    }

    public void setDef(int def) {
        this.def = def;
    }

    @Override
    public void defense(Attack attack) {
        // proccess 처리 완료에 상관없이 nextDefense를 무조건 호출해준다.
        proccess(attack);
        if (nextDefense != null) {
            nextDefense.defense(attack);
        }
    }

    private void proccess(Attack attack) {
        int amount = attack.getAmount();
        amount -= def;
        attack.setAmount(amount);
    }

    public void setNextDefense(Defense nextDefense) {
        this.nextDefense = nextDefense;
    }
}

메인 클래스를 구현
[Main.java]

package com.bkjeon.chain_of_responsibility.example2;

public class Main {

    public static void main(String[] args) {
        Attack attack = new Attack(100);

        Armor armor1 = new Armor(10);
        Armor armor2 = new Armor(15);

        armor1.setNextDefense(armor2);
        armor1.defense(attack);
        System.out.println(attack.getAmount());
    }

}

실행결과

75
  • 책임 사슬 패턴은 하나의 객체만 책임을 지는게 아니고 여러 객체가 책임을 다 같이 지어도 된다.
  • 동적으로 구현할 수 있다.
    [Main.java]
      package com.bkjeon.chain_of_responsibility.example2;
    
      public class Main {
    
          public static void main(String[] args) {
              Attack attack = new Attack(100);
    
              Armor armor1 = new Armor(10);
              Armor armor2 = new Armor(15);
    
              armor1.setNextDefense(armor2);
              // 첫번째 공격
              armor1.defense(attack);
              System.out.println(attack.getAmount());
    
              /**
              * Point2
              */
              Defense defense = new Defense() {
                  @Override
                  public void defense(Attack attack) {
                      int amount = attack.getAmount();
                      attack.setAmount(amount -= 50);
                  }
              };
    
              /**
              * 동적으로도 책임사슬에 추가 할 수도 있다.
              */
              // 게임 도중에 추가 착용
              armor2.setNextDefense(defense);
    
              // 추가 착용하고 다시 공격을 당한다.
              attack.setAmount(100);
              // 두번째 공격
              armor1.defense(attack);
    
              System.out.println(attack.getAmount());
          }
    
      }
    
      // 실행결과
      75
      25
    

 

참고: https://www.inflearn.com/course/%EC%9E%90%EB%B0%94-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/dashboard

반응형

'Java & Kotlin > Java' 카테고리의 다른 글

[Design Pattern] Observer Pattern  (0) 2020.01.05
[Design Pattern] Facade Pattern  (0) 2020.01.04
[Design Pattern] Visitor Pattern  (0) 2020.01.01
[Design Pattern] Decorator Pattern  (0) 2019.12.28
yyyy-MM-dd 형태의 날짜 조회 방법  (0) 2019.12.26
Comments