strategy pattern design pattern

Head First design pattern learning, conventions start with code and end with definitions.

Duck duck game, to design a game, the initial requirement is that there are various ducks in the game, and each duck looks different.

This is very easy to implement. A parent class has a method quack() that can croak, a method swim() that can swim, and an abstract method display() that represents appearance. Different subclasses inherit it and implement their own appearance. Just do it.


//Duck parent class
public abstract class Duck {

	public void quack(){
		System.out.println("Cawk");
	}
	public void swim(){
		System.out.println("游泳");
	}
	
	public abstract void display();
}
// red head duck implementation
public class RedHeadDuck extends Duck{

	@Override
	public void display() {
		System.out.println("Red head duck duck head is red");
	}

}
The red-headed duck inherits the parent class, then he can croak and swim, and realize his own appearance. It seems so good.

Next, the game needs to be changed, and it is required to add flying ducks. Can we write it directly in the parent class? We should know that not all ducks can fly. But it seems that it can also be written in the parent class, because we can use the subclass to override the parent class method. But it should be considered that if multiple flightless ducks are added in the future, each flightless duck will have to overwrite the parent class method, which is not a good phenomenon. Even what if some ducks don't croak, or croak and just squeak? Should subclasses be overridden? It seems we have to think of other ways to do this game.


Then how about we extract the flying method fly() and the calling method quack(), and extract the two interfaces Flyable and Quackable. The parent class Duck only has the swim() method and an abstract display() method, after all every duck can swim. As long as it is a subclass, it inherits the parent class. If it can fly, it implements the Flyable interface and implements the fly method. Whatever it is called, it implements the Quackable interface and implements the quack() method. But to think that most ducks can croak and croak, then we have to implement Flyable and the methods in each class are the same, the repeated code will increase, and if you want to change the behavior of crowing, you will need to modify the code a lot. . It's a nightmare, can't reuse, a lot of repetitive code. It seems that this method is not good either. RubberDuck, can't fly


What is the reason for the above problem? Mainly because fly and quack are mutable for subclasses, we can't predict the specific behavior of each duck. How to solve it? Can I separate the specific behaviors of fly and quack into a group, then Duck, subclass Duck, and specific behaviors are separated. How is the specific behavior used after this? Subclasses directly inherit? Obviously not subclasses have to inherit the parent class Duck; parent class inheritance? What's the difference between that and the first version you started doing; the subclass holds the reference? The code is repeated a lot, and each subclass must have these two references; then only the parent class can hold two references, which is the only good solution, but we also want the subclass to specify its own behavior, the parent class The reference must not be a specific class, it should be an interface, and all specific behaviors should implement a unified interface.

FlyBehavior and QuackBehavior are two interfaces, and FlyWithWings implements classes for FlyBehavior, which can fly. FlyNoWay implements classes for FlyBehavior. Can't fly. Quack, Squeck, and NoQuack are the implementation classes of QuackBehavior, which represent quack, squeak, and can't do anything.

Duck holds references to two interfaces, and has two methods to call the interface's methods. Of course, it can be dynamically set, and both interfaces have set methods. Let's go to code

public interface QuackBehavior {

	public void quack();
}
public interface FlyBehavior {

	public void fly();
}
public class FlyWithWings implements FlyBehavior{

	@Override
	public void fly() {
		System.out.println("fly");
	}

}
public class Squack implements QuackBehavior {

	@Override
	public void quack() {
		System.out.println("Squeak");
	}

}
public abstract class Duck {

	protected FlyBehavior flyBehavior;
	protected QuackBehavior quackBehavior;
	
	public void quack(){
		quackBehavior.quack();
	}
	
	public void fly(){
		flyBehavior.fly();
	}
	public void setFlyBehavior(FlyBehavior flyBehavior) {
		this.flyBehavior = flyBehavior;
	}
	public void setQuackBehavior(QuackBehavior quackBehavior) {
		this.quackBehavior = quackBehavior;
	}
	
	public abstract void display();
	
}
public class RedHeadDuck extends Duck{
	public RedHeadDuck(){
		flyBehavior=new FlyNoWay();
		quackBehavior=new Quack();
	}
	@Override
	public void display() {
		System.out.println("Red-headed duck");
	}
}
public class Test {

	public static void main(String[] args) {
		Duck duck=new RedHeadDuck();
		duck.quack();
		duck.fly();
		duck.setFlyBehavior(new FlyWithWings());
		duck.setQuackBehavior(new Squack());
		duck.quack();
		duck.fly();
	}
}

The result of the test is

croak
can not fly
squeak
fly

It can be seen that the behavior of the duck can be dynamically changed in the middle. At this time, if new ducks are added, there are different behaviors, and then the behavior class can be created directly. Even if the original behavior is changed, as long as the behavior class is changed, neither the Duck nor the application class needs to be changed.

Definition of Cero Mode: The Cero Mode defines a family of algorithms, which are encapsulated separately so that they can be replaced with each other. This mode allows the changes of the algorithm to be independent of the customers who use the algorithm.

In contrast to the explanation, the algorithm family refers to the behavior classes, namely fly and quack. We encapsulate the interfaces separately, and each behavior is encapsulated as a class. It can be replaced with each other, that is, it becomes interface-oriented, has set method, and can dynamically change behavior. In the end, real customers don't care about the implementation of your algorithm at all, and have nothing to do with themselves.





Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324852211&siteId=291194637