策略模式深入解析

场景模拟

Joe的公司做了一套模拟鸭子的游戏,游戏中会出现各种鸭子,可以一遍游泳戏水,一边呱呱叫。系统采用标准的OO技术,类图如下:



因为公司处于上升期,所以需要开发个牛逼的类型的鸭子,将竞争者甩在后头:会飞的鸭子。Joe毕竟是个OO程序员,这对他没什么难度


这样呢,就实现了红头、绿头会飞的鸭子,效果还不错哦!!


在股东会议上,由于之前Jack在程序中加入了一款橡皮鸭子,这个鸭子只是一种摆设鸭子,所以呢它不会飞,但可以发出吱吱的叫声,这样的话,屏幕上就出现了个可怕的场景:橡皮鸭子在飞!!!,股东很不开心!!



Joe想到的解决方法呢,依旧是继承,橡皮鸭子不能叫,那在子类覆盖默认实现就好!


        

可是,之后若要再加入一种诱饵鸭,它既不会叫,也不会飞,该如何?按照上述的方法,又得覆盖queck()和fly()方法

Joe发现,在之前的继承中方案中,每当有新的鸭子出现时,他都要去检查fly()quack()方法,这简直是无穷无尽的噩梦

重新整理思路,Joe觉得改用接口实现的方式去做



那么新的问题又来了:公司需要加入48种会飞的鸭子,Joe要手动实现了48个子类的fly()方法!而且其中大多数fly的方式都是大同小异,这样代码量明显增大!

思考:

1、继承并不是适当的解决方式

2、抽取FlyableQuackable接口能解决一部分问题,让子类实现接口,会造成代码无法复用

重新整理思路:

抽取FlyableQuackable接口能解决一部分问题,但因为无法复用代码,那么需要一种方法,能够解决这一问题

新的设计原则:

把会变化的部分抽取出来进行封装,一般以后可以改动或扩充,从而不会影响不需要变化的部分

针对接口编程,而不是针对实现编程

之前的做法是,鸭子飞行、叫声的行为都来自超类的实现,或者是子类实现接口并有子类自行去实现,这两种实现都是依赖于实现编程

       

正确做法:针对接口编程,这里的接口,可以是一个抽象类或一个接口



在这种新的设计中,实际的实现,不会绑死在鸭子的子类中,具体的实现在FlyBehavior的实现类中,同理QuackBehavior也是一样

修改后



多用组合(HAS-A),少用继承(IS-A

其实上述的就是策略模式

策略模式定义:定义算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户

面向对象的准则:

1、封装变化

2、多用组合,少用继承

3、针对接口编程,不针对实现编程

具体代码实现:

抽象出Duck抽象类,以及FlyBehavior接口和QuackBehavior接口

public interface FlyBehavior {
	void fly();
}

public interface QuackBehavior {
	void quack();
}

public abstract class Duck {
	FlyBehavior flyBehavior;
	QuackBehavior quackBehavior;
	
	public abstract void dispaly();
	
	public void peformFly() {
		flyBehavior.fly();
	}
	
	public void peformQuack() {
		quackBehavior.quack();
	}
	
	public void swim() {
		System.out.println("所有的鸭都能浮在水面哦!诱饵鸭也行的!");
	};
}

FlyBehavior各实现类

public class FlyWithWings implements FlyBehavior{
	@Override
	public void fly() {
		System.out.println("我会飞哦,超开心的!!");
	}
}



public class FlyNoWay implements FlyBehavior{
	@Override
	public void fly() {
		System.out.println("我不会飞!!!好难过!!");
	}
}

QuackBehavior各实现类


public class Quack implements QuackBehavior{
	@Override
	public void quack() {
		System.out.println("呱呱呱呱叫!");
	}
}

public class Squeak implements QuackBehavior{
	@Override
	public void quack() {
		System.out.println("吱吱吱吱叫!");
	}
}

public class MuteQuack implements QuackBehavior{
	@Override
	public void quack() {
		System.out.println("我不会叫!!好忧伤!!");
	}
}

各类鸭的实现

public class MallarDuck extends Duck{
	
	public MallarDuck() {
		flyBehavior = new FlyWithWings();
		quackBehavior = new Quack();
	}
	
	@Override
	public void dispaly() {
		System.out.println("我是绿头鸭~~!");
	}
}

public class RubberDuck extends Duck{
	
	public RubberDuck() {
		flyBehavior = new FlyNoWay();
		quackBehavior = new Squeak();
	}
	
	@Override
	public void dispaly() {
		System.out.println("我是橡皮鸭~~!");
	}
}

public class DecoyDuck extends Duck{
	
	public DecoyDuck() {
		flyBehavior = new FlyNoWay();
		quackBehavior = new MuteQuack();
	}
	
	@Override
	public void dispaly() {
		System.out.println("我是诱饵鸭~~!");
	}
}

public class RedheadDuck extends Duck{
	
	public RedheadDuck() {
		flyBehavior = new FlyWithWings();
		quackBehavior = new Quack();
	}
	
	@Override
	public void dispaly() {
		System.out.println("我是红头鸭~~!");
	}
}
模拟调用:
调用:
Duck mallarDuck = new MallarDuck();//创建绿头鸭
mallarDuck.dispaly();//显示绿头鸭外观
mallarDuck.swim();//绿头鸭游泳啦!
mallarDuck.peformFly();//绿头鸭飞行!
mallarDuck.peformQuack();//绿头鸭呱呱叫

输出的结果:
我是绿头鸭~~!
所有的鸭都能浮在水面哦!诱饵鸭也行的!
我会飞哦,超开心的!!
呱呱呱呱叫!	
调用:
Duck rubberDuck = new RubberDuck();//创建橡皮鸭
rubberDuck.dispaly();//显示橡皮鸭外观
rubberDuck.swim();//橡皮鸭游泳啦!
rubberDuck.peformFly();//橡皮鸭不会飞!
rubberDuck.peformQuack();//橡皮鸭吱吱叫

输出的结果:
我是橡皮鸭~~!
所有的鸭都能浮在水面哦!诱饵鸭也行的!
我不会飞!!!好难过!!
吱吱吱吱叫!	
调用:
Duck decoyDuck = new DecoyDuck();//创建诱饵鸭
decoyDuck.dispaly();//显示诱饵鸭外观
decoyDuck.swim();//诱饵鸭游泳啦!
decoyDuck.peformFly();//诱饵鸭不会飞!
decoyDuck.peformQuack();//诱饵鸭不会叫!

输出的结果:
我是诱饵鸭~~!
所有的鸭都能浮在水面哦!诱饵鸭也行的!
我不会飞!!!好难过!!
我不会叫!!好忧伤!! 	

Android中的策略模式

Android中的ListViewsetAdapter()方法中的参数ListAdapter就用到了策略模式

接口及实现类如下:

public interface ListAdapter extends Adapter {}

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {}

public class ArrayAdapter<T> extends BaseAdapter implements Filterable, ThemedSpinnerAdapter()
ListView的setAdapter()方法如下:

public void setAdapter(ListAdapter adapter)

可以看到 ListAdapter 是一个接口,ArrayAdapter BaseAdapter 是它的实现类。 ListView 中的setAdapter()参数ListAdapter对象可根据子类动态传入具体的对象




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值