OOAD之策略模式(1)
在引入策略模式之前。先用一个小项目解释为什么要有策略模式。这是一个模拟鸭子的小游戏。最开始需求为,所有的鸭子都会叫以及都会游泳且叫声游泳姿势都一样。因此我们用原始OO的思维去编写代码时很容易做到
public abstract class Duck{
public void yuck(){
System.out.println("嘎嘎叫");
}
public void swim(){
Systrm.out.println("i am swim");
}
public abstract void display();
}
也就是封装一个超类。然后设置两个子类通用的方法,叫和游泳。此时再编写程序需要的各种不同的鸭子子类。他们都能够叫和游泳。此时编写一个测试类。
public class Test{
public static void main(String[] args){
Duck gDuck = new GreenDuck();
Duck rDuck = new RedDuck();
gDuck.display();
gDuck.yuck();
gDuck.swim();
rDuck.display();
rDuck.yuck();
rDuck.swim();
}
}
public class GreenHeadDuck extends Duck{
@override
public void display(){
System.out.println("绿头鸭");
}
}
public class RedHeadDuck extends Duck{
@override
public void display(){
System.out.println("红头鸭");
}
}
测试类的结果为:绿头鸭 嘎嘎叫 i am swim 红头鸭 嘎嘎叫 i am swim。这个完全没有问题。好的,现在游戏上线,市场火热,新需求来了。鸭子要会飞。那我们继续用OO的思维去想,
那么可以给超类Duck中设置一个通用的fly方法。让所有的鸭子都会飞。让我们把Duck的代码改一下。改成下面的
public abstract class Duck{
public void yuck(){
System.out.println("嘎嘎叫");
}
public void swim(){
Systrm.out.println("i am swim");
}
public abstract void display();
public void fly(){
System.out.println("i am flying");
}
}
好的,现在的确实现了鸭子会飞的功能,但是这也引起了一些问题。因为事实上不是所有的鸭子都会飞。你在超类中定义了方法。影响的是全部的子类。容易导致溢出的问题,也就是。有些子类不需要。但是你给它强制加了。好,那如果现在有些子类不会飞。我们继续用OO的思维去解决。那么可以在不会飞的子类中用重写去覆盖掉父类给他的方法。我们加入绿头鸭不会飞,我们修改以下绿头鸭的代码如下
public class GreenHeadDuck extends Duck{
@override
public void display(){
System.out.println("绿头鸭");
}
@override
public void fly(){
System.out.println("i can't fly")
}
}
好,可以通过在子类中覆盖来实现有些鸭子会费飞有些不会飞这个需求。但是在我们这个例子中鸭子种类少,这么玩没有关系。但如果由2000种鸭子呢。难道你要一个一个的去覆盖子类中的方法。
很明显就能看出单纯的面向对象,也就是OO的思想在设计这个需求的时候并不完善。那也有些人说,那我不在超类Duck中定义fly的方法。我在子类中去定义,谁会飞我就给谁定义。这其实和上面一样。如果子类基数大。那么你写的重复代码也会很多。那么OO中的代码复用就完全没有体现出来了。
因此,我们分析以下上面OO设计的问题所在。为什么会说这个设计不好。原因是在于它的行为和客户类没有分离。也就是“干什么” 和 “怎么干”没有分离开来。例如上面的例子。客户类中的fly是干什么,但是怎么干,fly里面怎么定义代码,他们没有分离。全部堆在客户类中,耦合度太高。导致,你的“怎么干“放在客户类中定义,无论你放在超类还是子类。都容易出问题,因此就导出了策略模式这个概念
策略模式是干嘛的,是去耦合的。它所做的就是把”干什么“和”怎么干“分离开来。把”怎么干“封装到一个策略接口或者抽象类中。然后编写一系列的怎么干算法封装起来。客户类中只需要调用这个算法就ok了
策略模式的两种标准点的定义:
图视:

环境对象(Context):该类中实现了对抽象策略中定义的接口或者抽象类的引用。
抽象策略对象(Strategy):它可由接口或抽象类来实现。
具体策略对象(ConcreteStrategy):它封装了实现同不功能的不同算法。
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换,策略模式让算法独立于使用它的客户而独立变化。
使这些算法在客户端调用它们的时候能够互不影响地变化。
策略模式:分别封装行为接口,实现算法族,超类中放行为接口对象。在子类中的构造方法中去实例化行为对象。原则就是:分离变化部分,封装接口,基于接口编程各种功能族,让行为算法的变化独立于算法的使用者。
使用策略模式的步骤:
1.分析变化的行为,拿出来进行封装成一个策略接口或者抽象类。然后定义该行为的多种实现算法。形成算法族
2.在客户超类中放策略接口。
3.在子类的构造方法中去具体实例化具体的策略算法
下面让我们看看用策略模式修改模拟鸭子的这个项目。
1.封装变化的部分。当前鸭子的变化行为为fly。有些会飞,有些不会飞。有些会飞的好,有些飞的不好。因此封装fly这个行为为一个策略接口。FlyObject
public interface FlyObject{
void fly();
}
接下来,编写项目中实现fly这个行为的多种算法。例如不会飞 nofly,飞的好,good fly,飞得不好 badfly。这三个行为族
public class NoFly implements FlyObject{
@override
public void fly(){
System.out.println("不会飞")
}
}
public class GoodFly implements FlyObject{
@override
public void fly(){
System.out.println("Good fly");
}
}
public class BadFly implements FlyObject{
@override
public void fly(){
System.out.println("bad fly");
}
}
之后在客户类的超类也就是Duck中放置策略接口,也就是FlyObject。
package com.lyh.strategy.duck; import com.lyh.strategy.flybehavior.FlyBehavior;
import com.lyh.strategy.yuckbehavior.YuckBehavior; public abstract class Duck { FlyBehavior flybehavior;
YuckBehavior yuckbehavior;
public Duck() { }; public void fly() {
flybehavior.fly();
} public void yuck() {
yuckbehavior.yuck();
} public abstract void display(); public void setFlyBehavior(FlyBehavior fb) {
this.flybehavior = fb;
} public void setYuckBehavior(YuckBehavior yb) {
this.yuckbehavior = yb;
} //这个方法子类通用,不会变化
public void swim() {
System.out.println("i am swim");
}
}
在客户类的子类中去实例化具体的策略接口算法。
package com.lyh.strategy.duck; import com.lyh.strategy.flybehavior.GoodFlyBehavior;
import com.lyh.strategy.yuckbehavior.GaGaYuckBehavior; public class GreenHeadDuck extends Duck { public GreenHeadDuck() {
flybehavior = new GoodFlyBehavior();
yuckbehavior = new GaGaYuckBehavior();
}
@Override
public void display() {
System.out.println("绿头鸭");
} }
package com.lyh.strategy.duck; import com.lyh.strategy.flybehavior.NoFlyBehavior;
import com.lyh.strategy.yuckbehavior.NoYuckBehavior; public class RedHeadDuck extends Duck { public RedHeadDuck() {
flybehavior = new NoFlyBehavior();
yuckbehavior = new NoYuckBehavior();
}
@Override
public void display() {
System.out.println("红头鸭");
} }
因此,通过这种方式,能够实现客户类中的行为和客户类相分离。把变化的行为独立出来。抽象成接口。这样如果有新的行为需求,可以直接在行为族中加入。如果有新的客户类对象。也可以让他们
具体选择的去实现行为族。达到降低耦合度的目的。 但是,策略模式也有缺点。也就是客户类必须了解策略行为族中的每一个算法的实现以及原理。只有全部知晓。客户类才能去区别调用他们而不会出错。这时策略模式必须要做到的一点。
我们什么时候使用策略模式:这个没有具体的需求。一般而言。如果你定义的抽象父类中的一些方法是可变的。子类中不一定需要这些方法的时候。建议用策略模式将变化的行为封装起来。这其实也是一种方法的封装。你将行为封装,那么其他的类也可以去使用。
OOAD之策略模式(1)的更多相关文章
- 8.6 GOF设计模式四: 策略模式… Strategy Pattern
策略模式… Strategy Pattern 在POS系统中,有时需要实行价格优惠, 该如何处理? 对普通客户或新客户报全价 对老客户统一折扣5% 对大客户统一折扣10% 注:课件 ...
- javascript设计模式:策略模式
前言 策略模式有效利用组合.委托.多态等技术和思想,可以有效避免多重条件选择语句. 策略模式对开放-封闭原则提供了很好的支持,将算法封装在strategy中,使得他们易于切换.理解.扩展. 策略模式中 ...
- StrategyPattern (策略模式)
/** * 策略模式 * @author TMAC-J * 根据环境的不同选择不同的策略,把策略用接口抽象出来 */ public class StrategyPattern { interface ...
- JAVA 设计模式之策略模式
定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换. 类型:行为类模式 策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换.在前面说过 ...
- Java设计模式之策略模式(Strategy)
前言: 最近一直在学习基于okHttp网络请求,学习的过程中就想起了之前项目中有这么一个需求不同的接口要采用不同的加密方式,比如登录之前要采用RSA加密,登录之后要采用AES加密,当时是采用靠传递一个 ...
- 设计模式(一):“穿越火线”中的“策略模式”(Strategy Pattern)
在前段时间呢陆陆续续的更新了一系列关于重构的文章.在重构我们既有的代码时,往往会用到设计模式.在之前重构系列的博客中,我们在重构时用到了“工厂模式”.“策略模式”.“状态模式”等.当然在重构时,有的地 ...
- 《Head First 设计模式》之策略模式
作者:Grey 原文地址:http://www.cnblogs.com/greyzeng/p/5915202.html 模式名称 策略模式(Strategy Pattern) 需求 模拟鸭子游戏,游戏 ...
- 学C#之设计模式系列笔记(1)策略模式
一.借鉴说明 1.<Head First Design Patterns>(中文名<深入浅出设计模式>) 2.维基百科,策略模式,https://zh.wikipedia.or ...
- PHP 策略模式
策略模式:定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化.策略模式把对象本身和运算规则区分开来,其功能非常强大,因为这个设计模式本身的核心思想 ...
随机推荐
- 《UNP》学习之TCP状态转换
CLOSED:TCP起始状态 LISTEN:绑定端口后进入listen状态,一般是服务端 SYN_SENT:发送SYN连接请求,主动打开连接的一方进入SYN_SENT SYN_RCVD:接收到SYN连 ...
- CHECKDB内部:什么是BlobEater?
DBCC CHECKDB注意到有关数据文件页面.一旦整个表的所有页(或一组表,如果配料已启用-看到同样的博客文章我上面提到的),所有的事实都聚集在一起,他们都应该相互抵消.当有额外的事实(在索引B树都 ...
- RobotFrame连接MySql数据库
RobotFrame连接MySql数据库这类的教程网上并不多,就算有,也是很多坑.小编今天为大家提供一个靠谱的教程,但是具体的包需要大家自己下载.废话不多说,看疗效~~~ 1.pip install ...
- jBPM学习之利用API完成流程实例
流程引擎对象ProcessEngine是jBPM4所有的Service API之源.在jBPM4中各种服务相互依存,但所有的Service API都从ProcessEngine中获得,由此可见Proc ...
- 什么是TNB?如何买TNB?
我天天在微博上看到有人吹TNB,今天一起来看下它到底是什么玩意? 什么是TNB? Time New Bank (TNB) 旨在打造精淮的时间价值传输网络. 我们高度认可人们时间付出的商业价值,每个 ...
- 使用GitHub+hexo搭建个人独立博客
前言 使用github pages服务搭建博客的好处有: 全是静态文件,访问速度快: 免费方便,不用花一分钱就可以搭建一个自由的个人博客,不需要服务器不需要后台: 可以随意绑定自己的域名,不仔细看的话 ...
- Linux常用命令之文件处理命令
注:由于Linux操作系统有些目录不能轻易操作,特此建议大家在家目录home,或root.tmp目录下练习命令,以免带来不必要的损失 一.查询目录中的内容:ls 命令格式:ls [选项] [文件或目录 ...
- ZooKeeper 状态机
ZAB状态机 QuorumPeer这个线程负责状态机的维护 @Override public void run() { ... try { /* * Main loop */ while (runni ...
- api接口写好了?想过(Accept,Content-Type)?返回类型json|xml?
api接口写好了?想过(Accept,Content-Type)?返回类型json|xml? 起因: - A,B. A调用B提供的api接口. - A:为毛你的接口返回的是xml格式的(浏览器访问)? ...
- CSS基础知识(display和visibility、overflow、文档流)
9.显示与隐藏 u display属性: (1)none:隐藏元素,不会再占有页面的任何空间,即不会影响布局. (2)inline:默认值.将元素[显示]为内联元素 (与HTML元素本身无关 ...