设计模式(JAVA)~1-设计模式之策略模式

前言

设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。
1995 年,GoF(Gang of Four,四人组/四人帮)合作出版了《设计模式:可复用面向对象软件的基础》一书,共收录了 23 种设计模式,从此树立了软件设计模式领域的里程碑,人称「GoF设计模式」。
本系列文章参考《面向对象与设计模式》,耿祥义、张跃平,清华大学出版社出版。
原创博客,仅供学习参考,若有错误请各位大佬指出。注意:转载请注明出处,谢谢合作。

概念

策略模式(别名:政策):定义一系列算法,把他们一个个封装起来,并且使它们可以相互替换,本模式使得算法可独立于使用它的客户而变化。策略模式分属于行为型模式。

策略模式的结构

  1. 策略(Strategy):策略是一个接口,该接口定义若干个算法标识即抽象方法。
  2. 上下文(Context):依赖于策略接口的类,上下文包含策略声明的变量,上下文中提供一个方法,该方法委托策略变量调用具体策略所实现的策略接口中的方法。
  3. 具体策略(ConcreteStrategy):实现策略接口的类,具体策略是实现策略接口所定义的抽象方法,即给出算法标识的具体算法。

策略模式各角色的 UML 类图如图所示: (StartUML作图)
在这里插入图片描述

说这么多废话,不如举个栗子

好,那么就

举个栗子

案例—模拟鸭子游戏(场景):
目前公司制作了一款模拟鸭子(Duck)的游戏,游戏中各种鸭子外观(display)各不同,可以发出叫声(quack)、做游泳运动(swim)等等。市场需要竞争力,现在想要模拟程序使得鸭子会飞(fly)来加大游戏市场。
问题:模拟游戏中不是所有鸭子都会飞,比如橡皮鸭(RubberDuck);游戏开发下一个阶段会更新产品,并且游戏规格会增加新的鸭子类型。每当有新的子类出现,开发人员要被迫检查每个子类并可能需要重写fly()和quack()方法。

如何解决?
1、使用继承:鸭子的行为在子类里不断变化,无法满足需求。
2、使用Flyable接口、Quackable接口:Java接口不具有实现代码,所以继承接口无法达到代码复用。
3、采用面向对象设计原则:把会变化的部分取出并封装,以便以后修改和扩充,不影响其他部分。

解决方法:
设计原则——独立应用中可能变化的,不要和不需要变化的代码混在一起;针对接口编程而不是针对实现编程。
分开变化和不会变化的部分。可能会变化的:fly()和quack()。
做法:将两个行为从Duck类中取出,建立一组新类来代表每个行为。
目标:“指定行为”到鸭子的实例,在鸭子类中包含设定行为的方法,使得程序运行过程中可以动态的改变鸭子的行为。
利用接口代表每个行为:FlyBehavior/QuackBehavior.
Duck类不负责实现fly和quack的接口,由一组其他类专门实现FlyBehavior和QuackBehavior.
行为类(由行为类而不是Duck类来实现行为接口)
Duck的子类将使用FlyBehavior/QuackBehavior所表示的行为(特定的具体行为编写在实现了接口FlyBehavior/QuackBehavior的类中)

最终优化后的类图:
在这里插入图片描述

实例具体代码

输入并编译Duck类:

public abstract class Duck{
	FlyBehaviorflyBehavior;
	QuackBehaviorquackBehavior;
	public Duck(){}
	public abstract void display();
	public void performFly(){
		flyBehavior.fly();}
	public void performQuack(){
		quackBehavior.quack();}
	public void swim(){
		system.out.println("All ducks float,evendecoys!");}
}

输入编译FlyBehavior接口与两个行为实现类FlyWithWings和FlyNoWay:

public interface FlyBehavior{
	public void fly();
}
public class FlyWithWings implements FlyBehavior{
	public void fly(){
		system.out.println("I am flying!!"); 
	}
}
public class FlyNoWay implements FlyBehavior{
	public void fly(){
	system.out.println("I can not fly."); 
	}
}

输入编译QuackBehavior接口与三个行为实现类Quack、MuteQuack和Squack:

public interface QuackBehavior{
	public void quack();
}
public class Quack implements QuackBehavior{
	public void quack() {
		system.out.println("Quack"); 
	}
}
public class MuteQuack implements QuackBehavior{
	public void quack() {
		system.out.println("Silence"); 
	}
}
public class Squack implements QuackBehavior{
	public void quack() {
	system.out.println("Squack"); 
	}
}

总结

设计背景
在软件开发中常常遇到这种情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能。

问题
如何让算法和对象分开来,使得算法可以独立于使用它的客户而变化?

方案
把一个类中经常改变或者将来可能改变的部分独立出来,作为一个接口,然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。
比如定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换,使得算法可独立于使用它的客户而变化,这就是策略模式。

适用情景
许多相关的类仅仅是行为有异。 “策略”提供了一种用多个行为中的一个行为来配置一个类的方法。即一个系统需要动态地在几种算法中选择一种。
①当一个应用程序需要实现一种特定的服务或者功能,而且该程序有多种实现方式时使用。
②一个类定义了多种行为 , 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。
③程序主要类(上下文角色)不希望暴露复杂的、与算法相关的数据结构,即可将算法封装到具体策略中。

优点:可以动态的改变对象的行为

  1. 策略类间可自由切换:由于策略类都实现同一个接口,所以使它们之间可以自由切换。
  2. 易于扩展:增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合“开-闭“原则,上下文和具体策略是松耦合关系。
  3. 避免使用多重条件选择语句:充分体现面向对象设计思想。

缺点

  1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
  2. 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。

注:总结中有部分参考博客 — Java设计模式之策略模式

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值