ООП для чайников. Паттерны проектирования. Цепочка ответственности (Chain of Responsibility)
Еще один паттерн, из группы поведенческих, — цепочка ответственности (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))); } }
Вот результат работы программы:
CarefulBehavoir::handle() attack!!! CarefulBehavoir::handle() run! CarefulBehavoir::handle() AttackBehavoir::handle() DefaultBehavoir::handle() waiting... AngryBehavoir::handle() attack!!! AngryBehavoir::handle() attack!!! AngryBehavoir::handle() CarefulBehavoir::handle() DefaultBehavoir::handle() waiting...
Видно как злость влияет на принятие благоразумных решений.
Пример, к сожалению, далек от совершенства но, надеюсь, общую идею иллюстрирует.
О статье
Вы сейчас читаете статью «ООП для чайников. Паттерны проектирования. Цепочка ответственности (Chain of Responsibility)»
- Написанную:
- 30.04.2010
- Категории:
- oop

Нет комментариев
Перейти к форме добавления комментария | comments rss[?] | trackback uri [?]