Паттерны. Цепочка ответственности. Chain of Responsibility

      Комментарии к записи Паттерны. Цепочка ответственности. Chain of Responsibility отключены

Главная Форумы Программирование Технология программирования Паттерны Паттерны. Цепочка ответственности. Chain of Responsibility

В этой теме 0 ответов, 1 участник, последнее обновление  Васильев Владимир Сергеевич 2 нед., 5 дн. назад.

  • Автор
    Сообщения
  • #4082

    Еще один паттерн, из группы поведенческих, — цепочка ответственности (chain of responsibility).

    Цепочка обязанностей выстраивает объекты составных частей приложения связанными между собой по цепочке, для передачи запроса на обработку от более низких, детализированных слоев системы к более высоким глобальным.

    Вот UML диаграмма:

    Классический пример это контекстная справка в Microsoft Office, вы можете нажать кнопку вопросительного знака и кликнуть на любом элементе интерфейса, а система попытается найти страницу справки, максимально соответствующую запрошенному элементу. Делается это следующим образом, — поскольку интерфейс системы иерархичен, то запрос справки начинает подниматься снизу вверх — от элемента по которому был произведен клик вверх, первый элемент который «возьмется дать ответ», и покажет справку.

    В моем случае Цепочку Ответственности иллюстрирует класс игрового юнита, поведение к которому приближается вражеский ююнит, и в зависимости от игровой ситуации мы решаем как он поступит. Я определил несколько поведений: DefaultBehavoir (бызовый класс с общим функционалом), CarefulBehavoir (осторожность), AttackBehavoir (смелость), AngryBehavoir (злость). Мы можем выстроить иерархию поведения так как захотим (при этом верхнее поведение играет более важную роль при принятии решений).

    Вот код примера:

    // IBehavoir.java
    package patterns.chain;
    public interface IBehavoir {
      public int handle(int distance, int power);
    }
    
    // DefaultBehavoir.java
    package patterns.chain;
    public class DefaultBehavoir implements IBehavoir {
      static public int WAIT = 0;
      static public int ATTACK = 1;
      static public int RUN = 2;
      protected DefaultBehavoir behavoir;
      protected Unit unit;
    
      public DefaultBehavoir(Unit unit) {
        this.unit = unit;
      }
    
      public int handle(int distance, int power) {
        if(behavoir != null) {
          return behavoir.handle(distance, power);
        } else {
          System.out.println("DefaultBehavoir::handle()");
          return DefaultBehavoir.WAIT;
        }
      }
    
      public DefaultBehavoir addBehavoir(DefaultBehavoir behavoir) {
        this.behavoir = behavoir;
        return this;
      }
    
       static public String getCode(int option) {
        switch(option) {
        case 1:
          return "attack!!!";
        case 2:
          return "run!";
        default:
          return "waiting...";
        }
      }
    }
    
    // CarefulBehavoir.java
    package patterns.chain;
    public class CarefulBehavoir extends DefaultBehavoir implements IBehavoir {
      public CarefulBehavoir(Unit unit) {
        super(unit);
      }
    
      public int handle(int distance, int power) {
        System.out.println("CarefulBehavoir::handle()");
        if(power < unit.getPower()) {
          if(distance < unit.getAttackDistance()) {
            return DefaultBehavoir.ATTACK;
          } else {
            return DefaultBehavoir.WAIT;
          }
        } else if((distance + 2 < unit.getAttackDistance()) && (power > unit.getPower())) {
          return DefaultBehavoir.RUN;
        }
        return super.handle(distance, power);
      }
    }
    
    // AttackBehavoir.java
    package patterns.chain;
    public class AttackBehavoir extends DefaultBehavoir implements IBehavoir {
      public AttackBehavoir(Unit unit) {
        super(unit);
      }
      public int handle(int distance, int power) {
        System.out.println("AttackBehavoir::handle()");
        if((distance < unit.getAttackDistance()) && (power < unit.getPower())) {
          return DefaultBehavoir.ATTACK;
        }
        return super.handle(distance, power);
      }
    }
    
    // AngryBehavoir.java
    package patterns.chain;
    public class AngryBehavoir extends DefaultBehavoir implements IBehavoir {
      public AngryBehavoir(Unit unit) {
        super(unit);
      }
      public int handle(int distance, int power) {
        System.out.println("AngryBehavoir::handle()");
        if((distance / 2 < unit.getAttackDistance()) && (power / 5 < unit.getPower())) {
          return DefaultBehavoir.ATTACK;
        }
        return super.handle(distance, power);
      }
    }
    
    // Unit.java
    package patterns.chain;
    public class Unit {
      protected int power;
      protected int attackDistance;
      private DefaultBehavoir behavoir;
      public Unit(int power, int attackDistance) {
        this.power = power;
        this.attackDistance = attackDistance;
      }
      public int getPower() {
        return power;
      }
      public int getAttackDistance() {
        return attackDistance;
      }
      protected void setBehavoir(DefaultBehavoir behavoir) {
        this.behavoir = behavoir;
      }
      protected DefaultBehavoir getBehavoir() {
        return behavoir;
      }
      public int processSituation(int distance, int power) {
        return behavoir.handle(distance, power);
      }
    }
    
    // TestApp.java
    package patterns.chain;
    public class TestApp {
      /**
      * @param args
      */
      public static void main(String[] args) {
        Unit unit = new Unit(5,10);
        unit.setBehavoir(
          new CarefulBehavoir(unit).addBehavoir(
            new AttackBehavoir(unit).addBehavoir(
              new DefaultBehavoir(unit)
            )
          )
        );
    
        System.out.println(DefaultBehavoir.getCode(unit.processSituation(1,1)));
        System.out.println(DefaultBehavoir.getCode(unit.processSituation(5,10)));
        System.out.println(DefaultBehavoir.getCode(unit.processSituation(20,5)));
      
        unit.setBehavoir(
          new AngryBehavoir(unit).addBehavoir(
            new CarefulBehavoir(unit).addBehavoir(
              new DefaultBehavoir(unit)
            )
          )
        );
        System.out.println(DefaultBehavoir.getCode(unit.processSituation(1,1)));
        System.out.println(DefaultBehavoir.getCode(unit.processSituation(7,20)));
        System.out.println(DefaultBehavoir.getCode(unit.processSituation(20,5)));
      }
    }
    

    Вот результат работы программы:

    Видно как злость влияет на принятие благоразумных решений.
    Пример, к сожалению, далек от совершенства но, надеюсь, общую идею иллюстрирует.

Для ответа в этой теме необходимо авторизоваться.