—-慢慢来比较快,虚心学技术—-
概念
指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法
该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户
角色:
抽象策略**:定义公共接口,各种不同的算法以不同方式实现该接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
具体策略**:实现了抽象策略定义的接口,提供具体的算法实现。
环境**:持有一个策略类的引用,最终给客户端调用。**
推演
需求**:恐龙描述,恐龙具有两个属性,咆哮和外观**
/*** 恐龙抽象*/abstract class Dinosaur{/*** 咆哮*/protected void roar(){System.out.println("恶龙咆哮");}/*** 外观*/abstract void display();}
恐龙实现:
/*** 棘龙 会游泳会跑*/class Spinosaurus extends Dinosaur{@Overridevoid display() {System.out.println("我是棘龙,我背上有道棘");}}/*** 霸王龙龙 会跑*/class TyrannosaurusRex extends Dinosaur{@Overridevoid display() {System.out.println("我是霸王龙,我脑子只有核桃大小");}}/*** 翼龙*/class Pterosaur extends Dinosaur{@Overridevoid display() {System.out.println("我是翼龙,我有双美丽的翅膀");}}
实例化调用:
Dinosaur spinosaurus = new Spinosaurus();spinosaurus.roar();spinosaurus.display();System.out.println("===================");Dinosaur tyrannosaurusRex = new TyrannosaurusRex();tyrannosaurusRex.roar();tyrannosaurusRex.display();System.out.println("===================");Dinosaur pterosaur = new Pterosaur();pterosaur.roar();pterosaur.display();
运行结果:
恶龙咆哮我是棘龙,我背上有道棘===================恶龙咆哮我是霸王龙,我脑子只有核桃大小===================恶龙咆哮我是翼龙,我有双美丽的翅膀
需求变动**:现给恐龙添加一个飞翔fly以及游泳swim属性**
反例1
在父类中新增fly方法以及swim方法,这样所有恐龙都直接继承了这两个能力
abstract class Dinosaur{/*** 咆哮*/protected void roar(){System.out.println("恶龙咆哮");}protected void fly(){System.out.println("我要飞得更高");}protected void swim(){System.out.println("我要游得更快");}/*** 外观*/abstract void display();}
问题来了,会游泳的只有棘龙,会飞的只有翼龙,霸王龙两种技能都不具备,所以又需要在子类中重写父类的方法:
/*** 棘龙 会游泳会跑*/class Spinosaurus extends Dinosaur{@Overridevoid display() {System.out.println("我是棘龙,我背上有道棘");}@Overridevoid fly() {System.out.println("老龙不会飞啊");}}/*** 霸王龙龙 会跑*/class TyrannosaurusRex extends Dinosaur{@Overridevoid display() {System.out.println("我是霸王龙,我脑子只有核桃大小");}@Overridevoid fly() {System.out.println("老龙不会飞啊");}@Overridevoid swim() {System.out.println("老龙不会游呐");}}/*** 翼龙*/class Pterosaur extends Dinosaur{@Overridevoid display() {System.out.println("我是翼龙,我有双美丽的翅膀");}@Overridevoid swim() {System.out.println("老龙不会游呐");}}
调用:
Dinosaur spinosaurus = new Spinosaurus();spinosaurus.roar();spinosaurus.fly();spinosaurus.swim();spinosaurus.display();System.out.println("===================");Dinosaur tyrannosaurusRex = new TyrannosaurusRex();tyrannosaurusRex.roar();tyrannosaurusRex.fly();tyrannosaurusRex.swim();tyrannosaurusRex.display();System.out.println("===================");Dinosaur pterosaur = new Pterosaur();pterosaur.roar();pterosaur.fly();pterosaur.swim();pterosaur.display();
结果:
恶龙咆哮老龙不会飞啊我要游得更快我是棘龙,我背上有道棘===================恶龙咆哮老龙不会飞啊老龙不会游呐我是霸王龙,我脑子只有核桃大小===================恶龙咆哮我要飞得更高老龙不会游呐我是翼龙,我有双美丽的翅膀
看似问题解决,实则加重了开发人员的负担,每新增一种类型的恐龙,都需要判断是否能飞和是否能有用,一旦少重写了方法,就会出现问题,且工作量太大
反例2
将上面并不全部符合(经常变化)的两个方法从父类抽离
/*** 会飞*/interface Flyable{//默认实现(jdk1.8后)default void fly(){System.out.println("我要飞得更高");}}/*** 会游泳*/interface Swimable{//默认实现(jdk1.8后)default void swim(){System.out.println("我要游得更快");}}
各子类拥有这两个特性的则实现相关接口:
/*** 棘龙 会游泳会跑*/class Spinosaurus extends Dinosaur implements Swimable{@Overridevoid display() {System.out.println("我是棘龙,我背上有道棘");}}/*** 霸王龙龙 会跑*/class TyrannosaurusRex extends Dinosaur {@Overridevoid display() {System.out.println("我是霸王龙,我脑子只有核桃大小");}}/*** 翼龙*/class Pterosaur extends Dinosaur implements Swimable{@Overridevoid display() {System.out.println("我是翼龙,我有双美丽的翅膀");}}
调用:
Spinosaurus spinosaurus = new Spinosaurus();spinosaurus.roar();spinosaurus.swim();spinosaurus.display();System.out.println("===================");TyrannosaurusRex tyrannosaurusRex = new TyrannosaurusRex();tyrannosaurusRex.roar();tyrannosaurusRex.display();System.out.println("===================");Pterosaur pterosaur = new Pterosaur();pterosaur.roar();pterosaur.swim();pterosaur.display();
结果:
恶龙咆哮我要游得更快我是棘龙,我背上有道棘===================恶龙咆哮我是霸王龙,我脑子只有核桃大小===================恶龙咆哮我要游得更快我是翼龙,我有双美丽的翅膀
看似实现了区分,实则没有减少工作量,假如飞行方法不一样,加入了和翼龙飞行方式不一样的恐龙,则需要在对应子类中重写fly方法,且程序员依旧需要重复判断新增恐龙需不需要实现上述两个接口。
正例(策略模式)
彻底抽离特性,将飞行和游泳从实现和继承,转换成组合方式。
/*** 飞行行为*/interface FlyBehaviour{void fly();}/*** 游泳行为*/interface SwimBehaviour{void swim();}/*** 飞高高*/class FlyToHight implements FlyBehaviour{@Overridepublic void fly() {System.out.println("我要飞得更高");}}/*** 不会飞*/class FlyNoAble implements FlyBehaviour{@Overridepublic void fly() {System.out.println("老龙不会飞");}}/*** 游深深*/class SwimToDeep implements SwimBehaviour{@Overridepublic void swim() {System.out.println("我要游得更快");}}/*** 不会游泳*/class SwimNoAble implements SwimBehaviour{@Overridepublic void swim() {System.out.println("老龙不会游泳");}}
关联父类和上述两大特性
abstract class Dinosaur{protected FlyBehaviour flyBehaviour;protected SwimBehaviour swimBehaviour;/*** 咆哮*/protected void roar(){System.out.println("恶龙咆哮");}/*** 飞行*/protected void fly(){flyBehaviour.fly();}/*** 游泳*/protected void swim(){swimBehaviour.swim();}/*** 外观*/abstract void display();}
子类继承父类并关联上述两个特性
/*** 棘龙 会游泳会跑*/class Spinosaurus extends Dinosaur {public Spinosaurus(){this.flyBehaviour = new FlyNoAble();// 不会飞this.swimBehaviour = new SwimToDeep(); // 游泳}@Overridevoid display() {System.out.println("我是棘龙,我背上有道棘");}}/*** 霸王龙龙 会跑*/class TyrannosaurusRex extends Dinosaur {public TyrannosaurusRex() {this.flyBehaviour = new FlyNoAble();// 不会飞this.swimBehaviour = new SwimNoAble(); // 不会游泳}@Overridevoid display() {System.out.println("我是霸王龙,我脑子只有核桃大小");}}/*** 翼龙 会飞*/class Pterosaur extends Dinosaur {public Pterosaur() {this.flyBehaviour = new FlyToHight();// 飞高高this.swimBehaviour = new SwimNoAble(); // 不会游泳}@Overridevoid display() {System.out.println("我是翼龙,我有双美丽的翅膀");}}
调用
Dinosaur spinosaurus = new Spinosaurus();spinosaurus.roar();spinosaurus.fly();spinosaurus.swim();spinosaurus.display();System.out.println("===================");Dinosaur tyrannosaurusRex = new TyrannosaurusRex();tyrannosaurusRex.roar();tyrannosaurusRex.fly();tyrannosaurusRex.swim();tyrannosaurusRex.display();System.out.println("===================");Dinosaur pterosaur = new Pterosaur();pterosaur.roar();pterosaur.fly();pterosaur.swim();pterosaur.display();
结果:
恶龙咆哮老龙不会飞我要游得更快我是棘龙,我背上有道棘===================恶龙咆哮老龙不会飞老龙不会游泳我是霸王龙,我脑子只有核桃大小===================恶龙咆哮我要飞得更高老龙不会游泳我是翼龙,我有双美丽的翅膀
此时,如果需要扩展不同的飞行方式和游泳方式,仅需要创建类实现FlyBehaviour及SwimBehaviour接口,并关联新类即可,无需修改源码
上述例子中:
FlyBehaviour和SwimBehaviour为**抽象策略,实现这两个接口的类是具体策略,而持有这两两个策略的父类Dinosaur则是环境**
应用场景
系统需要动态选择几种算法中选择一种时
系统要求使用算法的客户不需要知道算法细节
各类之间区别只体现在表现行为不同
优点
灵活切换不同表现,避免更改源码,符合开闭原则
缺点
**
容易造成很多的具体策略类
如有贻误,还请评论指正
