ООП для чайников. Паттерны проектирования. Цепочка ответственности (Chain of Responsibility)

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

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

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

chain

Классический пример это контекстная справка в 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...

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

Comments

comments

Leave a reply:

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Site Footer

Sliding Sidebar

About Me

About Me

Для кого этот блог?

Для тех кого интересуют современные интернет технологи, IT бизнес, стартапы, менеджмент, контроль качества, личная эффективность, мотивация. Здесь я буду писать о том, что в первую очередь будет интересно мне, о проблемах и решениях. О том что пригодилось мне, и возможно будет интересно Вам.

Что заставило меня создать его?

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

Немного о себе.

Мой первый серьезный опыт в IT это работа над desktop приложениями в компании «Эксперт-Софт». У истоков её стояли несколько амбициозных и талантливых молодых людей, с огнем в глазах и желанием работать «как майкрософт». То чем мы там занимались вполне могли бы сегодня назвать «стартапом». Рук было откровенно мало, поэтому приходилось заниматься всем: кодированием на Delphi, написанием скриптов на VBA, дизайном, вёрсткой и поддержкой вебсайта, работой над рекламной полиграфией, проектированием интерфейсов и БД. Работы было много, но запал был велик, команда очень разношерстная, гармонично дополняя друг-друга в решении нетривиальных задач. Благодаря тому что пришлось попробовать многое, постепенно вырисовалось понимание того чем хочется заниматься, и как. Софтверным программированием я был сыт по горло. Массы проблем десктопного софта в вебе просто не было, по определению. Зато был четкий фокус на дизайне, юзабилити, скорости. Поэтому когда пришла пора уходить из «Эксперт-Софт», я без всякого сожаления стал искать работу как разработчик для web. Поскольку городишко у нас не очень большой, выбор был практически предопределен. Так я стал работать в «Оникс-Системз», где и продолжаю работать поныне. За время работы в компании я как разработчик принимал участие в работе над несколькими десятками проектов. Несколько десятков проектов было сделано мною как фрилансером. Самым большим проектом в котором я сыграл роль менеджера, считаю свою семью. Также довольно большой проект мы сейчас поднимаем с командой разработчиков (на данный момент команда состоит из четырех php разработчиков, одного flex кодера и тестировщика). Отсюда, большой интерес к современным практикам и методологиям, разным подходам в управлении командой, повышению эффективности и качества работы. По мере сил, вдохновения и свободного времени, я буду писать об этом.

Если у Вас возникли какие-то вопросы ко мне лично, буду рад если Вы свяжетесь со мной:

e-mail:
skype: denis.sheremetov
Старый сайт, с музычкой и флешом

Прочая онлайновая деятельность: