设计模式学习专栏一--------策略模式

策略模式

场景


设计鸭子模拟器系统,实现具有各种行为组合的鸭子

  • 刚开始设计时,此系统设计了标准的OO技术,设计了一个鸭子超类,并让各种鸭子继承此超类

问题引入 : "让鸭子会飞! 此程序需要会飞的鸭子(火箭喷射鸭)" "鸭子的叫声不同(橡皮鸭, 模型鸭)"

较差的实现方式

  • 在超类中增加fly()方法,并给予实现.

    • 所有的鸭子都将拥有飞行的能力,但是并不是所有的鸭子都能飞(橡皮鸭)

    • 解决: 让不会飞的鸭子重写fly方法,什么也不做

    • 思考: 如果系统后续有各种各样的行为要增加(假设有50个), 并且每种行为有多种实现,并且一个鸭子可能有各种行为的组合 , 那么不具备这些能力的鸭子都要进行重写,这是一个好的设计吗?

  • 将飞行行为定义成接口,让鸭子子类去实现

    • 假设现在有100种鸭子,定义一个飞行的接口, 需要让有飞行能力的鸭子全部进行重写, 这样一来代码会重复很多,这是一个差劲的设计.

如何解决


  • 问题出现在哪里?

继承的问题:对类的局部改动,尤其超类的局部改动,会影响所有子类部分。影响会有溢出效果

超类挖的一个坑,每个子类都要来填,增加工作量,复杂度O(N^2) (增加N个行为,每个行为N个类来改)。不是好的设计方式

  • 如何设计

    • 分离可变部分和不可变部分
      • 不经常变动部分: Duck类
      • 可变部分: 可能新增的各种行为 fly() , quack()
    • 这次鸭子类不会负责实现Flying和Quacking接口,反而是由我们制造一组其他类专门实现FlyingBehavior和QuackBehavior接口, 这称为"行为类", 由行为类而不是Duck类来实现行为接口
    • 关键在于,**鸭子现在会将飞行和呱呱叫的动作"委托"(delegate) 别人代理,而不是使用定义在Duck类(或子类)**内的呱呱叫和飞行方法
  • 类图设计

  • 重构后的分析
    • 鸭子需要什么行为组合都能自行决定
    • 可以在运行中动态改变自己的行为( setBehavior )

策略模式总结


定义:策略模式定义了算法族(行为族),分别封装起来,让它们之间可以相互替换,此模式让算法的变化部分 (鸭子行为) 独立于算法的客户(鸭子)

  • 模式的理解
    • 角色
      • 拥有行为的主体(鸭子)
      • 各种不同的行为,每种行为都有各种实现(飞行 / 叫声)
    • 细节
      • 主体使用组合行为的方式, 让主体任意的组合需要的行为
      • 可以在运行中动态改变自己的行为( setBehavior )

核心代码部分

  • 鸭子类
public abstract class Duck {
	FlyBehavior flyBehavior;		//飞行行为
	QuackBehavior quackBehavior;	//叫声行为

	public Duck() {
	}

	public void setFlyBehavior(FlyBehavior fb) {
		flyBehavior = fb;
	}

	public void setQuackBehavior(QuackBehavior qb) {
		quackBehavior = qb;
	}

	abstract void display();

	public void performFly() {
		flyBehavior.fly();
	}

	public void performQuack() {
		quackBehavior.quack();
	}

	public void swim() {
		System.out.println("All ducks float, even decoys!");
	}
}
复制代码
  • 行为接口 (飞行\叫声)

    public interface FlyBehavior {
    	public void fly();
    }
    
    public interface QuackBehavior {
    	public void quack();
    }
    复制代码
  • 实现行为接口

    //不会飞行
    public class FlyNoWay implements FlyBehavior {
    	public void fly() {
    		System.out.println("I can't fly");
    	}
    }
    //呱呱叫
    public class Quack implements QuackBehavior {
    	public void quack() {
    		System.out.println("Quack");
    	}
    }
    复制代码
  • 具体的鸭子

    //模型鸭, 不会飞,只会呱呱叫
    public class ModelDuck extends Duck {
    	public ModelDuck() {
    		flyBehavior = new FlyNoWay();
    		quackBehavior = new Quack();
    	}
    
    	public void display() {
    		System.out.println("I'm a model duck");
    	}
    }
    复制代码
  • 鸭子模拟器(主程序)

    public class MiniDuckSimulator {
    
    	public static void main(String[] args) {
    
    		MallardDuck	mallard = new MallardDuck();
    		RubberDuck	rubberDuckie = new RubberDuck();
    		DecoyDuck	decoy = new DecoyDuck();
    
    
    		mallard.performQuack();
    		rubberDuckie.performQuack();
    		decoy.performQuack();
    
    		Duck	 model = new ModelDuck();
    		model.performFly();
            //运行中改变行为
    		model.setFlyBehavior(new FlyRocketPowered());
    		model.performFly();
    	}
    }
    复制代码
  • 输出结果

    Quack
    Squeak
    << Silence >>
    I can't fly
    I'm flying with a rocket
    复制代码

参考

​ 书籍: HeadFirst设计模式

​ 代码参考地址: 我就是那个地址

转载于:https://juejin.im/post/5c851d7f6fb9a049a97a86e5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值