—-慢慢来比较快,虚心学技术—-

概念

指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法

该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户

角色:

抽象策略**定义公共接口,各种不同的算法以不同方式实现该接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现

具体策略**实现了抽象策略定义的接口,提供具体的算法实现

环境**持有一个策略类的引用,最终给客户端调用。**

推演

需求**:恐龙描述,恐龙具有两个属性,咆哮和外观**

  1. /**
  2. * 恐龙抽象
  3. */
  4. abstract class Dinosaur{
  5. /**
  6. * 咆哮
  7. */
  8. protected void roar(){
  9. System.out.println("恶龙咆哮");
  10. }
  11. /**
  12. * 外观
  13. */
  14. abstract void display();
  15. }

恐龙实现:

  1. /**
  2. * 棘龙 会游泳会跑
  3. */
  4. class Spinosaurus extends Dinosaur{
  5. @Override
  6. void display() {
  7. System.out.println("我是棘龙,我背上有道棘");
  8. }
  9. }
  10. /**
  11. * 霸王龙龙 会跑
  12. */
  13. class TyrannosaurusRex extends Dinosaur{
  14. @Override
  15. void display() {
  16. System.out.println("我是霸王龙,我脑子只有核桃大小");
  17. }
  18. }
  19. /**
  20. * 翼龙
  21. */
  22. class Pterosaur extends Dinosaur{
  23. @Override
  24. void display() {
  25. System.out.println("我是翼龙,我有双美丽的翅膀");
  26. }
  27. }

实例化调用:

  1. Dinosaur spinosaurus = new Spinosaurus();
  2. spinosaurus.roar();
  3. spinosaurus.display();
  4. System.out.println("===================");
  5. Dinosaur tyrannosaurusRex = new TyrannosaurusRex();
  6. tyrannosaurusRex.roar();
  7. tyrannosaurusRex.display();
  8. System.out.println("===================");
  9. Dinosaur pterosaur = new Pterosaur();
  10. pterosaur.roar();
  11. pterosaur.display();

运行结果:

  1. 恶龙咆哮
  2. 我是棘龙,我背上有道棘
  3. ===================
  4. 恶龙咆哮
  5. 我是霸王龙,我脑子只有核桃大小
  6. ===================
  7. 恶龙咆哮
  8. 我是翼龙,我有双美丽的翅膀

需求变动**:现给恐龙添加一个飞翔fly以及游泳swim属性**

反例1

在父类中新增fly方法以及swim方法,这样所有恐龙都直接继承了这两个能力

  1. abstract class Dinosaur{
  2. /**
  3. * 咆哮
  4. */
  5. protected void roar(){
  6. System.out.println("恶龙咆哮");
  7. }
  8. protected void fly(){
  9. System.out.println("我要飞得更高");
  10. }
  11. protected void swim(){
  12. System.out.println("我要游得更快");
  13. }
  14. /**
  15. * 外观
  16. */
  17. abstract void display();
  18. }

问题来了,会游泳的只有棘龙,会飞的只有翼龙,霸王龙两种技能都不具备,所以又需要在子类中重写父类的方法:

  1. /**
  2. * 棘龙 会游泳会跑
  3. */
  4. class Spinosaurus extends Dinosaur{
  5. @Override
  6. void display() {
  7. System.out.println("我是棘龙,我背上有道棘");
  8. }
  9. @Override
  10. void fly() {
  11. System.out.println("老龙不会飞啊");
  12. }
  13. }
  14. /**
  15. * 霸王龙龙 会跑
  16. */
  17. class TyrannosaurusRex extends Dinosaur{
  18. @Override
  19. void display() {
  20. System.out.println("我是霸王龙,我脑子只有核桃大小");
  21. }
  22. @Override
  23. void fly() {
  24. System.out.println("老龙不会飞啊");
  25. }
  26. @Override
  27. void swim() {
  28. System.out.println("老龙不会游呐");
  29. }
  30. }
  31. /**
  32. * 翼龙
  33. */
  34. class Pterosaur extends Dinosaur{
  35. @Override
  36. void display() {
  37. System.out.println("我是翼龙,我有双美丽的翅膀");
  38. }
  39. @Override
  40. void swim() {
  41. System.out.println("老龙不会游呐");
  42. }
  43. }

调用:

  1. Dinosaur spinosaurus = new Spinosaurus();
  2. spinosaurus.roar();
  3. spinosaurus.fly();
  4. spinosaurus.swim();
  5. spinosaurus.display();
  6. System.out.println("===================");
  7. Dinosaur tyrannosaurusRex = new TyrannosaurusRex();
  8. tyrannosaurusRex.roar();
  9. tyrannosaurusRex.fly();
  10. tyrannosaurusRex.swim();
  11. tyrannosaurusRex.display();
  12. System.out.println("===================");
  13. Dinosaur pterosaur = new Pterosaur();
  14. pterosaur.roar();
  15. pterosaur.fly();
  16. pterosaur.swim();
  17. pterosaur.display();

结果:

  1. 恶龙咆哮
  2. 老龙不会飞啊
  3. 我要游得更快
  4. 我是棘龙,我背上有道棘
  5. ===================
  6. 恶龙咆哮
  7. 老龙不会飞啊
  8. 老龙不会游呐
  9. 我是霸王龙,我脑子只有核桃大小
  10. ===================
  11. 恶龙咆哮
  12. 我要飞得更高
  13. 老龙不会游呐
  14. 我是翼龙,我有双美丽的翅膀

看似问题解决,实则加重了开发人员的负担,每新增一种类型的恐龙,都需要判断是否能飞和是否能有用,一旦少重写了方法,就会出现问题,且工作量太大

反例2

将上面并不全部符合(经常变化)的两个方法从父类抽离

  1. /**
  2. * 会飞
  3. */
  4. interface Flyable{
  5. //默认实现(jdk1.8后)
  6. default void fly(){
  7. System.out.println("我要飞得更高");
  8. }
  9. }
  10. /**
  11. * 会游泳
  12. */
  13. interface Swimable{
  14. //默认实现(jdk1.8后)
  15. default void swim(){
  16. System.out.println("我要游得更快");
  17. }
  18. }

各子类拥有这两个特性的则实现相关接口:

  1. /**
  2. * 棘龙 会游泳会跑
  3. */
  4. class Spinosaurus extends Dinosaur implements Swimable{
  5. @Override
  6. void display() {
  7. System.out.println("我是棘龙,我背上有道棘");
  8. }
  9. }
  10. /**
  11. * 霸王龙龙 会跑
  12. */
  13. class TyrannosaurusRex extends Dinosaur {
  14. @Override
  15. void display() {
  16. System.out.println("我是霸王龙,我脑子只有核桃大小");
  17. }
  18. }
  19. /**
  20. * 翼龙
  21. */
  22. class Pterosaur extends Dinosaur implements Swimable{
  23. @Override
  24. void display() {
  25. System.out.println("我是翼龙,我有双美丽的翅膀");
  26. }
  27. }

调用:

  1. Spinosaurus spinosaurus = new Spinosaurus();
  2. spinosaurus.roar();
  3. spinosaurus.swim();
  4. spinosaurus.display();
  5. System.out.println("===================");
  6. TyrannosaurusRex tyrannosaurusRex = new TyrannosaurusRex();
  7. tyrannosaurusRex.roar();
  8. tyrannosaurusRex.display();
  9. System.out.println("===================");
  10. Pterosaur pterosaur = new Pterosaur();
  11. pterosaur.roar();
  12. pterosaur.swim();
  13. pterosaur.display();

结果:

  1. 恶龙咆哮
  2. 我要游得更快
  3. 我是棘龙,我背上有道棘
  4. ===================
  5. 恶龙咆哮
  6. 我是霸王龙,我脑子只有核桃大小
  7. ===================
  8. 恶龙咆哮
  9. 我要游得更快
  10. 我是翼龙,我有双美丽的翅膀

看似实现了区分,实则没有减少工作量,假如飞行方法不一样,加入了和翼龙飞行方式不一样的恐龙,则需要在对应子类中重写fly方法,且程序员依旧需要重复判断新增恐龙需不需要实现上述两个接口。

正例(策略模式)

彻底抽离特性,将飞行和游泳从实现和继承,转换成组合方式。

  1. /**
  2. * 飞行行为
  3. */
  4. interface FlyBehaviour{
  5. void fly();
  6. }
  7. /**
  8. * 游泳行为
  9. */
  10. interface SwimBehaviour{
  11. void swim();
  12. }
  13. /**
  14. * 飞高高
  15. */
  16. class FlyToHight implements FlyBehaviour{
  17. @Override
  18. public void fly() {
  19. System.out.println("我要飞得更高");
  20. }
  21. }
  22. /**
  23. * 不会飞
  24. */
  25. class FlyNoAble implements FlyBehaviour{
  26. @Override
  27. public void fly() {
  28. System.out.println("老龙不会飞");
  29. }
  30. }
  31. /**
  32. * 游深深
  33. */
  34. class SwimToDeep implements SwimBehaviour{
  35. @Override
  36. public void swim() {
  37. System.out.println("我要游得更快");
  38. }
  39. }
  40. /**
  41. * 不会游泳
  42. */
  43. class SwimNoAble implements SwimBehaviour{
  44. @Override
  45. public void swim() {
  46. System.out.println("老龙不会游泳");
  47. }
  48. }

关联父类和上述两大特性

  1. abstract class Dinosaur{
  2. protected FlyBehaviour flyBehaviour;
  3. protected SwimBehaviour swimBehaviour;
  4. /**
  5. * 咆哮
  6. */
  7. protected void roar(){
  8. System.out.println("恶龙咆哮");
  9. }
  10. /**
  11. * 飞行
  12. */
  13. protected void fly(){
  14. flyBehaviour.fly();
  15. }
  16. /**
  17. * 游泳
  18. */
  19. protected void swim(){
  20. swimBehaviour.swim();
  21. }
  22. /**
  23. * 外观
  24. */
  25. abstract void display();
  26. }

子类继承父类并关联上述两个特性

  1. /**
  2. * 棘龙 会游泳会跑
  3. */
  4. class Spinosaurus extends Dinosaur {
  5. public Spinosaurus(){
  6. this.flyBehaviour = new FlyNoAble();// 不会飞
  7. this.swimBehaviour = new SwimToDeep(); // 游泳
  8. }
  9. @Override
  10. void display() {
  11. System.out.println("我是棘龙,我背上有道棘");
  12. }
  13. }
  14. /**
  15. * 霸王龙龙 会跑
  16. */
  17. class TyrannosaurusRex extends Dinosaur {
  18. public TyrannosaurusRex() {
  19. this.flyBehaviour = new FlyNoAble();// 不会飞
  20. this.swimBehaviour = new SwimNoAble(); // 不会游泳
  21. }
  22. @Override
  23. void display() {
  24. System.out.println("我是霸王龙,我脑子只有核桃大小");
  25. }
  26. }
  27. /**
  28. * 翼龙 会飞
  29. */
  30. class Pterosaur extends Dinosaur {
  31. public Pterosaur() {
  32. this.flyBehaviour = new FlyToHight();// 飞高高
  33. this.swimBehaviour = new SwimNoAble(); // 不会游泳
  34. }
  35. @Override
  36. void display() {
  37. System.out.println("我是翼龙,我有双美丽的翅膀");
  38. }
  39. }

调用

  1. Dinosaur spinosaurus = new Spinosaurus();
  2. spinosaurus.roar();
  3. spinosaurus.fly();
  4. spinosaurus.swim();
  5. spinosaurus.display();
  6. System.out.println("===================");
  7. Dinosaur tyrannosaurusRex = new TyrannosaurusRex();
  8. tyrannosaurusRex.roar();
  9. tyrannosaurusRex.fly();
  10. tyrannosaurusRex.swim();
  11. tyrannosaurusRex.display();
  12. System.out.println("===================");
  13. Dinosaur pterosaur = new Pterosaur();
  14. pterosaur.roar();
  15. pterosaur.fly();
  16. pterosaur.swim();
  17. pterosaur.display();

结果:

  1. 恶龙咆哮
  2. 老龙不会飞
  3. 我要游得更快
  4. 我是棘龙,我背上有道棘
  5. ===================
  6. 恶龙咆哮
  7. 老龙不会飞
  8. 老龙不会游泳
  9. 我是霸王龙,我脑子只有核桃大小
  10. ===================
  11. 恶龙咆哮
  12. 我要飞得更高
  13. 老龙不会游泳
  14. 我是翼龙,我有双美丽的翅膀

此时,如果需要扩展不同的飞行方式和游泳方式,仅需要创建类实现FlyBehaviour及SwimBehaviour接口,并关联新类即可,无需修改源码

上述例子中:
FlyBehaviour和SwimBehaviour为**抽象策略,实现这两个接口的类是具体策略,而持有这两两个策略的父类Dinosaur则是环境**

应用场景

系统需要动态选择几种算法中选择一种时

系统要求使用算法的客户不需要知道算法细节

各类之间区别只体现在表现行为不同

优点

灵活切换不同表现,避免更改源码,符合开闭原则

隐藏算法细节,提高代码可读性
**

缺点

**
容易造成很多的具体策略类

如有贻误,还请评论指正