设计模式学习(一)——策略模式

  前段时间买了一本书《Head First设计模式》,看了第一章后才对设计模式的概念有少许了解:它其实是开发过程中很多前人的经验与智慧的总结,帮助你在开发时采取更好的方式去设计各个类、方法、以及它们之间的调用、实现方式,让代码保持灵活性的同时又能更好地复用。基于学过一块知识一定要用文字记录、总结、巩固,而不是走马观花的原则,趁最近终于有空,特将前一段时间看的关于“策略模式”的内容总结于此。

场景描述

A公司要做一套模拟鸭子的游戏,游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫,还有一些会飞。

方案1 继承

设计一个超类Duck,包含方法quack()、swim()、fly()分别模拟鸭子的叫、游泳、飞行等行为,再包含一个抽象类display(),用于展示各个鸭子不同的外观,让每个鸭子子类继承父类时实现display()。

弊端:

这样做的好处是,每个鸭子子类继承父类时就同时拥有了父类的方法,可以达到代码复用的目的,但是这样会使某些并不适合该行为的子类也具有该行为。如果某些子类鸭子,如“橡皮鸭”,它不具备某些功能(如飞行),它就不应该拥有这个飞行的功能。当然,你可以在子类中通过@Override覆盖这个方法。但是当各个不同的子类都需要通过覆盖修改不同的方法时,就会非常繁琐,而且容易出现纰漏,且这些新覆盖的方法不能被复用。如“橡皮鸭”只会叫不会飞,“木头鸭”不会叫也不会飞。以后每当有新的鸭子子类出现,你都要去检查并可能需要覆盖这些方法,想想都让人抓狂。

方案2 接口

在超类Duck中将quack()、fly()等可变的方法用接口Quackable(),Flyable()来代替,然后在每个鸭子子类中,如果具有“飞行”或“叫”这个功能就实现“飞行“或”叫“这个接口。

弊端:

代码无法复用,如果有100个子类,都具有飞行的行为,你就需要重复100次代码。

设计模式来帮忙

设计原则一:找出程序中可能需要变化的地方和不需要变化的地方,将它们独立开来。让系统中的某部分改变不会影响其他部分。

由于fly()和quack()会随着鸭子的不同而改变,所以把这两个行为从Duck类中分开,建一组新类来代表各个行为。

设计原则二:针对接口编程,而不是针对实现。

利用多态,针对超类型编程,执行时根据实际状况执行到真正的行为,不会被绑死在超类型的行为上。以前的做法是:行为来自超类的具体实现或是继承某个接口并由子类自行实现。这两种方法都捆绑于”实现“,无法方便地更改行为。现在我们利用接口代表每个行为,比如FlyBehavior,QuackBehavior,然后让各个行为类实现这些接口,然后在Duck类中只要定义这个接口的实例变量即可,这样在各个鸭子子类中如果想拥有某种特定的行为,只要用这个接口实例变量去引用具体的行为类即可。

设计原则三:多用组合,少用继承。

飞行和叫这两种不同的行为,我们分别为其建立两组不同的行为类,然后在Duck类中通过接口实例变量结合起来,这就是”组合“。使得系统具有很大的弹性,还可以”在运行时动态地改变行为“。

下面就是经过重新设计后的应用代码:

1.应用的目录结构图

2.接口FlyBehavior

1 public interface FlyBehavior {
2     public void fly();
3 }

3.接口QuackBehavior

1 public interface QuackBehavior {
2     public void quack();
3 }

4.Fly行为的一个实现——FlyNoWay

1 public class FlyNoWay implements FlyBehavior{
2     @Override
3     public void fly() {
4         System.out.println("I can not fly.");
5     }
6 }

5.Fly行为的另一个实现——FlyWithWings

1 public class FlyWithWings implements FlyBehavior {
2     @Override
3     public void fly() {
4         System.out.println("I can fly!");
5     }
6 }

6.Fly行为的又另一个实现——FlyRocketPowered

1 public class FlyRocketPowered implements FlyBehavior{
2     @Override
3     public void fly() {
4         System.out.println("I am flying with a rocket.");
5     }
6 }

7.父类Duck

 1 public abstract class Duck {
 2     FlyBehavior flyBehavior;
 3     QuackBehavior quackBehavior;
 4     public abstract void display();
 5     public void performFly(){
 6         flyBehavior.fly();
 7     }
 8     public void performQuack(){
 9         quackBehavior.quack();
10     }
11     public void setFlyBehavior(FlyBehavior fb){
12         this.flyBehavior = fb;
13     }
14     public void setQuackBehavior(QuackBehavior qb){
15         this.quackBehavior=qb;
16     }
17 }

8.Duck的一个子类——绿头鸭MallardDuck

 1 public class MallardDuck extends Duck{
 2     public MallardDuck() {
 3         flyBehavior = new FlyWithWings();
 4         quackBehavior = new QuackWithGuaGua();
 5     }
 6
 7     @Override
 8     public void display() {
 9         System.out.println("I am a MallardDuck.");
10
11     }
12 }

9.Duck的另一个子类——模型鸭ModelDuck

 1 public class ModelDuck extends Duck {
 2     public ModelDuck() {
 3         flyBehavior = new FlyNoWay();
 4         quackBehavior = new QuackNoWay();
 5     }
 6
 7     @Override
 8     public void display() {
 9         System.out.println("I am a ModelDuck.");
10     }
11 }

10.应用模拟器(执行主类):MiniDuckSimulator

 1 public class MiniDuckSimulator {
 2
 3     public static void main(String[] args) {
 4         Duck mallardDuck = new MallardDuck();
 5         mallardDuck.display();
 6         mallardDuck.performFly();
 7         mallardDuck.performQuack();
 8         Duck modelDuck = new ModelDuck();
 9         modelDuck.display();
10         modelDuck.performFly();
11         modelDuck.performQuack();
12         modelDuck.setFlyBehavior(new FlyRocketPowered());
13         modelDuck.performFly();
14     }
15
16 }

执行代码,得到的结果如下:

总结

策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。这是书里给出的策略模式的定义,依我个人的理解,这种模式的关键就是要将系统中的可变行为抽象出来,单独进行封装,用一组行为类(算法族)来实现该特定的接口,这样任何类(如Duck)如果想拥有这些算法族中的某个算法,都可以通过定义接口实例变量而拥有该整个算法族,在子类中再对该变量进行赋值。像这个例子里,通过定义了FlyBehavior,这样以后任何想有飞行行为的类如飞机,都可以调用这个接口及实现它的各个飞行类。且飞行行为的变化可以通过增加新的飞行类来实现,不会对其他部分(如quack()、display()等行为,亦或是已拥有某些特定飞行行为的对象)造成任何影响,即”算法的变化独立于使用算法的客户“。而且各个飞行行为之间也可以互相替换。即 setFlyBehavior(Flybehavior fb)

可见,设计模式的应用让整个项目的代码拥有了极大的灵活性,且达到了代码复用的效果。设计模式其实是一种设计上的思维方式,是前人的智慧和经验的总结,其真正的精髓不是看过就能学会的,还是需要在实际应用中不断地实践摸索,慢慢体会。

文章中如果有任何问题,欢迎大家指正。

时间: 2024-08-29 14:25:36

设计模式学习(一)——策略模式的相关文章

设计模式学习笔记--策略模式

定义: 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化. 我们在使用一些功能时,有时有很多种实现方法,或者多种结果,但是都有同样的使用方法,即调用接口,这就是策略模式. 例子: // 设计模式Demo.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> #include <string> using namespa

设计模式学习之--策略模式

策略模式是什么:首先,策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化.说的有点不太容易理解,在我们面向对象的思想中一般都是结合我们的生活实例,举个现实的例子,我们的动物中有多种不同的鸟,它们都会飞行,都会走路,但它们的飞行方式不同,有些是翱翔,有些是燕子那样飞行,也有会像俯飞的(这个例子有点挫),但是鸟都会飞,它们的飞行策略是不同的,这里飞行就是不同的算法,或许很多不同的鸟会采用一种的飞行方式,也有的鸟不会飞行.这些策略就

&lt;C/C++ 版&gt; 设计模式 学习之 策略模式

策略模式(strategy):它定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的用户. 在下面的情况下应当考虑使用策略模式: 1. 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为. 2. 一个系统需要动态地在几种算法中选择一种.那么这些算法可以包装到一个个的具体算法类里面,而这些具体算法类都是一个抽象算法类的子类.换言之,这些具体算法类均 有统一的接口,由于多态性原则,客户端可

&lt;C/C++ 版&gt; 设计模式 学习之 策略模式+工厂模式

策略模式是一种定义一系列算法的方法,从概念上来讲,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方法调用所有的算法,减少各种算法类与使用算法类之间的耦合. 策略模式的 strategy (COperate)类层为 context 定义了一些了可供重用的算法或者行为,继承有助于析取这些算法中的公公功能. 策略模式简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试. 每个算法可以保证自身没有错误 ,修改其中的一个不会影响到其他算法. 测试代码如下: //Stra_F

设计模式学习之策略模式

一个报价管理系统 在一些CRM(客户关系管理)系统中,会有一个单独的报价管理模块,处理复杂的报价功能 普通客户:全价 老客户:根据年限,给予折扣 大客户:根据累计消费,给予折扣 客户购买量:对于新老客户都适用 报价人员职位高低: 如何实现???? 一个支付策略的接口 package com.cmc; //一个报价接口类,提供报价的接口,传入的参数为钱数 public interface OfferSuper { public abstract double offerCash(double mo

设计模式学习之策略模式:容错恢复机制

容错恢复机制 应用程序开发中常见的功能 程序运行的时候,正常情况下应该按某种方式来做,如果按照某种方式来做发生错误的话,系统并不会崩溃,而是继续运行,能提供出错后的备用方案. 日志记录的例子 把日志记录到数据库和日志记录到文件当做两种记录日志的策略 日志记录的策略接口: package com.cmc; public interface LogStrategy { public void SaveLog(String msg); } 把日志写到文件的策略: package com.cmc; pu

设计模式进阶(一) 策略模式

摘自<Design Paterns_Elements of Reusable Object-Oriented Software> 上一系列偏重于入门,从本篇开启进阶系列,着重于设计模式的适用情景. 回顾入门系列 设计模式入门(一)  策略模式 1  Intent Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary

设计模式学习之-状态模式

一.状态模式状态模式,当一个对象的内在状态发生改变时允许改变其行为行为,这个对象像是改变了其子类.状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况.把状态的判断逻辑转移到表示不同的状态的一系列类当中,可以把复杂的判断逻辑简化.当然,如果这个状态判断比较简单,那就没有必要用“状态模式”了.这段话有点难以理解,简而言之就是,在一类中根据当前状态去实例化下一状态子类.下面是状态模式结构图. State类,是一个抽象状态类,定义一个接口以封装与Context的特定状态相关的行为.

设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也经常遇到类似的情况,实现某一个功能有多种算法或者策略,我们能够依据环境或者条件的不同选择不同的算法或者策略来完毕该功能.如查找.排序等,一种经常使用的方法是硬编码(Hard Coding)在一个类中,如须要提供多种查找算法,能够将这些算法写到一个类中,在该类中提供多个方法,每个方法相应一个详细的查找算法:当然也能够将这些查找算法封装在一个统一的方法中,通过if-else-或者case等条件推断语句来进行选择.

设计模式学习02—工厂模式

1.动机与定义 我们在程序中使用一个对象时,需要new一下,如果需要设置其他值就再初始化一下.比如我要使用一个按钮,手动new一个矩形按钮,然后初始化一些值,如显示文字,背景色等. // 矩形按钮 IButton btn = new RecButton(); // 初始化其他值 btn.setText("提交"); btn.setBackgroundColor("#00aaff"); // 其他初始化省略 // 圆形按钮 IButton btn2 = new Rou