1.举例分析
问题:
要想实现一套模拟鸭子的游戏,鸭子种类很多,有绿头鸭、红头鸭、橡皮鸭和诱饵鸭。鸭子动作很多,动作包括叫法和飞行,且不同种类鸭子叫法不同,飞行行为不同。
难点:
鸭子种类和鸭子动作都会随着业务的改变而发生扩展或减少。
怎么办?
2.定义:策略模式
策略模式:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
3.设计原则
3.1 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
解释:
1.如果每次新的需求一来,都会使某方面的代码发生变化,那么你就可以确定,这部分代码需要被抽出来,和其他稳定的代码有所区分。
2.可以使得系统中的某部分改变不会影响其他部分。
3.2 针对接口编程,而不是针对实现编程。
解释:
1.利用接口代表每个行为,而行为的每个实现都将实现其中的一个接口。
2.可以通过增加和减少行为类,来增加和减少操作,而不是修改代码。
3.使用接口“实现”,不会被绑定在特定的对象中,也就是“针对超类型编程”
3.3 多用组合,少用继承。
解释:
1.使用组合建立系统具有很大的弹性,不仅可以将算法族(行为库)封装成类,更可以在“运行时改变行为”,只要组合的行为对象符合正确的接口标准。
2.“组合”用在很多设计模式中。
4.解决办法:策略模式图片解释
4.1 定义FlyBehavior行为接口
//所有飞行行为必须实现的接口
public interface FlyBehavior{
public void fly();
}
实现接口,也就是写很多飞行行为的算法。
1.行为一:FlyNoWay行为类(新建)
public class FlyNoWay implements FlyBehavior {
public void fly() {
//这是飞行行为的实现,给“不会”飞的鸭子使用,包括橡皮鸭和诱饵鸭
System.out.println("I can't fly!");
}
}
2.行为二: FlyRocketPowered行为类(新建)
//建立一个利用火箭动力飞行的行为
public class FlyRocketPowered implements FlyBehavior{
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("I'm flying with a rocket!");
}
}
3.行为三: FlyWithWings行为类(新建)
public class FlyWithWings implements FlyBehavior {
public void fly() {
//这是飞行行为的实现,给“真会”飞的鸭子使用
System.out.println("I'm flying!!");
}
}
备注:要是在实际业务中,这类的行为不够用,还可以动态地扩展和缩减。是不是很有弹性?
4.2 定义QuackBehavior行为接口
public interface QuackBehavior {
public void quack();
}
实现接口,也就是写很多呱呱叫行为的算法。
1.行为一:MuteQuack行为类(新建)
public class MuteQuack implements QuackBehavior{
public void quack() {
System.out.println("<<Silence!>>");
}
}
2.行为二:Quack行为类(新建)
public class Quack implements QuackBehavior{
public void quack() {
System.out.println("Quack!");
}
}
2.行为三:Squeak行为类(新建)
public class Squeak implements QuackBehavior{
public void quack() {
System.out.println("Squeak!");
}
}
备注:要是在实际业务中,这类的行为不够用,还可以动态地扩展和缩减。是不是很有弹性?
4.3 定义Duck超类
定义Duck超类,如果需要新增加一种类型的鸭子,就来继承这个Duck超类。
import FlyBehavior.FlyBehavior;
import QuackBehavior.QuackBehavior;
public abstract class Duck {
//行为变量被申明为“行为接口”类型,所有鸭子子类(在同一个package中)都继承它们。
//每只鸭子都会引用实现FlyBehavior接口的对象
FlyBehavior flyBehavior;
//每只鸭子都会引用实现QuackBehavior接口的对象
QuackBehavior quackBehavior;
public Duck() {
};
//抽象方法,
public abstract void display();
public void performFly() {
//鸭子对象不亲自处理呱呱叫行为,而是委托给flyBehavior引用的对象
flyBehavior.fly();
}
public void performQuack() {
//鸭子对象不亲自处理呱呱叫行为,而是委托给quackBehavior引用的对象
quackBehavior.quack();
}
public void swim() {
System.out.println("All ducks float, even decoys!");
}
//注意下面方法的添加,很经典
//从此以后,我们可以随时调用这两个方法改变鸭子的行为
public void setFlyBehavior(FlyBehavior fb) {
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb) {
quackBehavior = qb;
}
}
4.4 加入业务来了,增加一些种类的鸭子
这时候突然来了一个鸭子(MallardDuck),那么就继承Duck超类,建立一种类型的鸭子出来:
//绿头鸭
public class MallardDuck extends Duck {
//别忘了,因为MallardDuck继承Duck类,所以具有flyBehavior与quackBehavior实例变量
/*
*FlyBehavior flyBehavior;
*QuackBehavior quackBehavior;
*/
public MallardDuck() {
//绿头鸭使用Quack类处理呱呱叫,叫的职责被委托给Quack对象。
quackBehavior = new Quack();
//使用FlyWithWings作为其FlyBehavior类型
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("I'm a real Mallard duck!");
}
}
这时候又来了一个鸭子(ModelDuck),那么就继续继承Duck超类,建立一种新类型的鸭子出来:
import FlyBehavior.FlyNoWay;
import QuackBehavior.Quack;
public class ModelDuck extends Duck{
//别忘了,因为ModelDuck继承Duck类,所以具有flyBehavior与quackBehavior实例变量
/*
*FlyBehavior flyBehavior;
*QuackBehavior quackBehavior;
*/
public ModelDuck() {
//一开始,模型鸭是不会飞的
flyBehavior = new FlyNoWay();
quackBehavior = new Quack();
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("I'm a model duck!");
}
}
要是新业务来了,我们又可以增加新的子类鸭子啦,不用更改原来的代码。这样就容易扩展,代码很有弹性。
5.测试一下
import FlyBehavior.FlyRocketPowered;
public class MiniDuckSimulator {
public static void main(String[] args) {
//这会调用MallardDuck继承来的performQuack()方法,进而委托给该对象的QuackBehavior对象处理
//也就是说:调用继承来的quackBehavoir引用对象的quack()方法。
Duck mallard = new MallardDuck();
mallard.performQuack();
mallard.performFly();
mallard.display();
mallard.swim();
System.out.println("--------------------------------");
Duck model = new ModelDuck();
model.performFly();
model.setFlyBehavior(new FlyRocketPowered());
model.performFly();
}
}
输出:
Quack!
I'm flying!!
I'm a real Mallard duck!
All ducks float, even decoys!
--------------------------------
I can't fly!
I'm flying with a rocket!
结合图片解释看,更容易理解噢!
要是觉得上面的代码难敲,这里有下载方式(运行环境Eclipse,语言:Java):
提取码:hoke