问题场景
现在我们设计好了以下类

超类鸭子,不同的鸭子外观是不一样的,所以展示的方法是抽象的方法。不同种类的鸭子都继承duck,并重写展示方法。
需求-----鸭子是可以飞的
有一天项目经理说:“鸭子是可以飞的”。那么这个时候,你也许会直接想到要不直接在超类里面写一个fly的方法。这样所有继承的鸭子都可以实现fly的方法。
貌似这样好像没有什么问题,这样所有的子类都可以实现飞翔。

bug---塑料鸭子在天上飞
随着项目的进行,项目里面需要创建一个塑料鸭子的类,根据我们的oo设计原则,我们应该继承duck类。这样就会有个问题
塑料鸭子也具备了天上飞的方法,想想是不是有点毛骨悚然。所有继承的问题就出现了:虽然很多时候,继承都能够完成代码的复用,但是破坏了封装,不是所有的鸭子都是可以飞翔的。继承是不能够采用了。
改进---实现接口
这时候,你肯定会想到既然继承不行,那我就实现接口。写一个flyable接口,每一个可以飞的鸭子类我实现它这样的话,就可以解决塑料鸭子在天上飞的问题了。
问题---代码复用度不够
虽然解决了塑料鸭子在天上飞的问题,但是有一个隐藏的问题:复用度不够,代码反复写。这里只有两种鸭子,但是如果有二十多种鸭子呢?难道我们要写二十多次?聪明的程序员都是会偷懒的。那么有没有种简单的方式,解决这种问题呢?
解决---成员变量实现
划重点
设计原则
找出应用中可能变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
在这里飞行是变化的部分,不是所有的鸭子都是可以飞翔的。所以我们需要将这个行为提取出来,组建成一个新的类来代表飞行的行为。

我不清楚这样的uml表达是否是准确的所以我也贴上代码:
抽象父类duck
package com.yyh.StrategyPattern;
/**
* 抽象父类
*/
public abstract class Duck {
private FlyBehavior flyBehavior;
public void swimming(){
System.out.println("duck.swimming");
}
public void quack(){
System.out.println("duck.quack");
}
public abstract void display();
public FlyBehavior getFlyBehavior() {
return flyBehavior;
}
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
}
MallardDuck
package com.yyh.StrategyPattern;
public class MallardDuck extends Duck {
private FlyBehavior flyBehavior;
@Override
public void display(){
System.out.println("MallardDuck.绿头");
}
}
RedheadDuck
package com.yyh.StrategyPattern;
public class RedheadDuck extends Duck {
private FlyBehavior flyBehavior;
@Override
public void display(){
System.out.println("RedheadDuck.红头");
}
}
RubberDuck
package com.yyh.StrategyPattern;
public class RubberDuck extends Duck {
@Override
public void display(){
System.out.println("RedheadDuck.塑料的");
}
}
FlyBehavior
package com.yyh.StrategyPattern;
public interface FlyBehavior {
void fly();
}
FlyWithWings
package com.yyh.StrategyPattern;
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("通过翅膀飞行");
}
}
FlyNoWay
package com.yyh.StrategyPattern;
public class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
System.out.println("原地蹦跶了一下");
}
}
测试类
package com.yyh.StrategyPattern;
public class TestMain {
public static void main(String[] args) {
Duck mallardDuck = new MallardDuck();
mallardDuck.setFlyBehavior(new FlyWithWings());
Duck redheadDuck = new RedheadDuck();
redheadDuck.setFlyBehavior(new FlyWithWings());
Duck rubberDuck = new RubberDuck();
rubberDuck.setFlyBehavior(new FlyNoWay());
System.out.println("mallardDuck:");
mallardDuck.getFlyBehavior().fly();
System.out.println("redheadDuck:");
redheadDuck.getFlyBehavior().fly();
System.out.println("rubberDuck:");
rubberDuck.getFlyBehavior().fly();
}
}
测试结果

分析
这样的话,我们没有删除曾经的业务逻辑,只是添加了一个成员变量就解决了不同鸭子的飞行问题。并且通过set方式的话,可以在程序运行的时候,动态改变行为。
动态改变行为
如果我们在运行的过程中,给红头鸭子一个火箭,让它坐火箭飞行呢?其实我们就只需要写一个新的飞的实现类就可以了。在程序指定的位置set一下,就可以改变鸭子的行为了,
FlyWithRocket
package com.yyh.StrategyPattern;
public class FlyWithRocket implements FlyBehavior {
@Override
public void fly() {
System.out.println("坐火箭,惊了~~");
}
}
新的测试类
package com.yyh.StrategyPattern;
public class TestMain {
public static void main(String[] args) {
Duck mallardDuck = new MallardDuck();
mallardDuck.setFlyBehavior(new FlyWithWings());
Duck redheadDuck = new RedheadDuck();
redheadDuck.setFlyBehavior(new FlyWithWings());
Duck rubberDuck = new RubberDuck();
rubberDuck.setFlyBehavior(new FlyNoWay());
System.out.println("mallardDuck:");
mallardDuck.getFlyBehavior().fly();
System.out.println("redheadDuck:");
redheadDuck.getFlyBehavior().fly();
System.out.println("rubberDuck:");
rubberDuck.getFlyBehavior().fly();
System.out.println("==动态修改状态====:");
//坐火箭上天
redheadDuck.setFlyBehavior(new FlyWithRocket());
System.out.println("redheadDuck:");
redheadDuck.getFlyBehavior().fly();
}
}
测试结果

笔记
设计原则
少用继承,多用组合
策略模式定义
定义了算法簇,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用与算法的客户。
喜欢和评论是我更新和学习的最大动力,谢谢!
网友评论