ООП для чайников. Паттерны проектирования. Цепочка ответственности (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...

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

Site Footer

Sliding Sidebar

About Me

About Me

For whom this blog for?

For those who are interested in modern Internet technologies, IT business, startups, management, quality control, personal effectiveness, motivation. Here I write about what is interesting, about problems I faced and solutions I found. I hope it will be interesting to you either.

What motivates me to write?

The desire to improve, to study deeper topics that interest me. Find people with similar problems and tasks, together look for ways out and solutions.

Feel free to contact if you have anything to say to me

Old Flash site with my artistic works and misuc.