设计模式—策略模式 状态模式
一 策略模式
应用场景
1、 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。
3、 对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
优点
1、 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码转移到父类里面,从而避免重复的代码。
2、 策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。
3、 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。
缺点
1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
2、 策略模式造成很多的策略类,每个具体策略类都会产生一个新类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。
源代码:
public interface MemberStrategy { /** * 计算图书的价格 * @param booksPrice 图书的原价 * @return 计算出打折后的价格 */ public double calcPrice(double booksPrice); } public class PrimaryMemberStrategy implements MemberStrategy { @Override public double calcPrice(double booksPrice) { System.out.println("对于初级会员的没有折扣"); return booksPrice; } } public class IntermediateMemberStrategy implements MemberStrategy { @Override public double calcPrice(double booksPrice) { System.out.println("对于中级会员的折扣为10%"); return booksPrice * 0.9; } } public class AdvancedMemberStrategy implements MemberStrategy { @Override public double calcPrice(double booksPrice) { System.out.println("对于高级会员的折扣为20%"); return booksPrice * 0.8; } } public class Price { //持有一个具体的策略对象 private MemberStrategy strategy; /** * 构造函数,传入一个具体的策略对象 * @param strategy 具体的策略对象 */ public Price(MemberStrategy strategy){ this.strategy = strategy; } /** * 计算图书的价格 * @param booksPrice 图书的原价 * @return 计算出打折后的价格 */ public double quote(double booksPrice){ return this.strategy.calcPrice(booksPrice); } } public class Client { public static void main(String[] args) { //选择并创建需要使用的策略对象 MemberStrategy strategy = new AdvancedMemberStrategy(); //创建环境 Price price = new Price(strategy); //计算价格 double quote = price.quote(300); System.out.println("图书的最终价格为:" + quote); } }
二 状态模式
/// <summary> /// 电灯类,对应模式中的Context类 /// </summary> public class Light { private LightState state; public Light(LightState state) { this.state = state; } /// <summary> /// 按下电灯开关 /// </summary> public void PressSwich() { state.PressSwich(this); } public LightState State { get { return state; } set { state = value; } } } /// <summary> /// 抽象的电灯状态类,相当于State类 /// </summary> public abstract class LightState { public abstract void PressSwich(Light light); } /// <summary> /// 具体状态类, 开 /// </summary> public class On : LightState { /// <summary> /// 在开状态下,按下开关则切换到关的状态。 /// </summary> /// <param name="light"></param> public override void PressSwich(Light light) { Console.WriteLine("Turn off the light."); light.State = new Off(); } } /// <summary> /// 具体状态类,关 /// </summary> public class Off: LightState { /// <summary> /// 在关状态下,按下开关则打开电灯。 /// </summary> /// <param name="light"></param> public override void PressSwich(Light light) { Console.WriteLine("Turn on the light."); light.State = new On(); } } class Program { static void Main(string[] args) { // 初始化电灯,原始状态为关 Light light = new Light(new Off()); // 第一次按下开关,打开电灯 light.PressSwich(); // 第二次按下开关,关闭电灯 light.PressSwich(); Console.Read(); } }
三 两种模式的区别
区别:
状态模式将各个状态所对应的操作分离开来,即对于不同的状态,由不同的子类实现具体操作,不同状态的切换由子类实现,当发现传入参数不是自己这个状态所对应的参数,则自己给Context类切换状态;而策略模式是直接依赖注入到Context类的参数进行选择策略,不存在切换状态的操作
状态模式将各个状态所对应的操作分离开来,即对于不同的状态,由不同的子类实现具体操作,不同状态的切换由子类实现,当发现传入参数不是自己这个状态所对应的参数,则自己给Context类切换状态;而策略模式是直接依赖注入到Context类的参数进行选择策略,不存在切换状态的操作
联系:
状态模式和策略模式都是为具有多种可能情形设计的模式,把不同的处理情形抽象为一个相同的接口,符合对扩展开放,对修改封闭的原则。