设计模式-策略模式
2016-01-21 17:40
435 查看
设计模式-策略模式
策略模式(Strategy Pattern):策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。同时策略类也叫上下文类(Context)。
策略模式的结构
•封装类:也叫上下文,对策略进行二次封装,目的是避免高层模块对策略的直接调用。
•抽象策略:通常情况下为一个接口,当各个实现类中存在着重复的逻辑时,则使用抽象类来封装这部分公共的代码,此时,策略模式看上去更像是模版方法模式。
•具体策略:具体策略角色通常由一组封装了算法的类来担任,这些类之间可以根据需要自由替换。
这篇文章在是前面文章工厂方法模式的基础上加入策略模式,所以在下面的示例代码中你会看到策略模式和工厂方法模式的结合全用。
许多人分不清工厂方法模式和策略模式的区别,感觉很像,所以我把这二个模式结合起来使用,这样你就更容易理解这二者之间的区别。这里简单说明下
工厂方法:关注对象创建
策略模式:关注对象行为
先来看下模型图
下面来看下具体代码
基类抽象工厂的策略类
基类PC的策略类
调用方式
运行结果
I am Dell-Strategy personal computer
I am IBM-Strategy personal computer
请按任意键继续…
改进一下把二个策略合并
调用方式
运行结果
I am Dell-StrategyMix personal computer
I am IBM-StrategyMix personal computer
请按任意键继续…
策略模式的优缺点
•策略类之间可以自由切换,由于策略类实现自同一个抽象,所以他们之间可以自由切换。
•易于扩展,增加一个新的策略对策略模式来说非常容易,基本上可以在不改变原有代码的基础上进行扩展。
•避免使用多重条件,如果不使用策略模式,对于所有的算法,必须使用条件语句进行连接,通过条件判断来决定使用哪一种算法,在上一篇文章中我们已经提到,使用多重条件判断是非常不容易维护的。
•维护各个策略类会给开发带来额外开销,可能大家在这方面都有经验:一般来说,策略类的数量超过5个,就比较令人头疼了。
•必须对客户端(调用者)暴露所有的策略类,因为使用哪种策略是由客户端来决定的,因此,客户端应该知道有什么策略,并且了解各种策略之间的区别,否则,后果很严重。例如,有一个排序算法的策略模式,提供了快速排序、冒泡排序、选择排序这三种算法,客户端在使用这些算法之前,是不是先要明白这三种算法的适用情况?再比如,客户端要使用一个容器,有链表实现的,也有数组实现的,客户端是不是也要明白链表和数组有什么区别?就这一点来说是有悖于迪米特法则的。
版权所有,转载请注明文章出处 http://blog/csdn.net/cadenzasolo
策略模式(Strategy Pattern):策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。同时策略类也叫上下文类(Context)。
策略模式的结构
•封装类:也叫上下文,对策略进行二次封装,目的是避免高层模块对策略的直接调用。
•抽象策略:通常情况下为一个接口,当各个实现类中存在着重复的逻辑时,则使用抽象类来封装这部分公共的代码,此时,策略模式看上去更像是模版方法模式。
•具体策略:具体策略角色通常由一组封装了算法的类来担任,这些类之间可以根据需要自由替换。
这篇文章在是前面文章工厂方法模式的基础上加入策略模式,所以在下面的示例代码中你会看到策略模式和工厂方法模式的结合全用。
许多人分不清工厂方法模式和策略模式的区别,感觉很像,所以我把这二个模式结合起来使用,这样你就更容易理解这二者之间的区别。这里简单说明下
工厂方法:关注对象创建
策略模式:关注对象行为
先来看下模型图
下面来看下具体代码
abstract class PC { private string name; public PC(string name) { this.name = name; } //public virtual string Name { get; set; } public string Name { get { return name; } set { name = value; } } public abstract void Describe(); }
class Dell : PC { public Dell(string name) : base(name) { } public override void Describe() { System.Console.WriteLine("I am {0} personal computer", Name); } }
class IBM : PC { public IBM(string name) : base(name) { } public override void Describe() { System.Console.WriteLine("I am {0} personal computer", Name); } }
abstract class Factory { public abstract PC Create(); //public abstract PC Create(string name); }
class DellFactory : Factory { public override PC Create() { return new Dell("Dell"); } //public override PC Create(string name) { return new Dell(name); } }
class IBMFactory : Factory { public override PC Create() { return new IBM("IBM"); } //public override PC Create(string name) { return new IBM(name); } }
class StrategyF //错误的工厂策略 { public PC DellStrategy() { return new DellFactory().Create(); } public PC IBMStrategy() { return new IBMFactory().Create(); } //假设这里再来个HP和Sony,那还要写多少个方法 }
class StrategyP //错误的基类策略 { PC pc; public string Name { get { return pc.Name; } set { pc.Name = value; } } public StrategyP(PC pc) { this.pc = pc; } public void DellDescription() { var d = new Dell("dell"); d.Name = pc.Name; d.Describe(); //new Dell("dell").Describe(); } public void IBMDescriptiony() { new IBM("ibm").Describe(); } //假设这里再来个HP和Sony,那还要写多少个方法 }
基类抽象工厂的策略类
class StrategyFactory //Factory Strategy { Factory f; public StrategyFactory(Factory f) { this.f = f; } public PC Create() { return f.Create(); } }
基类PC的策略类
class StrategyPC //PC Strategy { PC pc; public string Name { get { return pc.Name; } set { pc.Name = value; } } public StrategyPC(PC pc) { this.pc = pc; } public void Describe() { pc.Describe(); } }
调用方式
//错误的策略,虽然能正确调用。 //StrategyF stf = new StrategyF(); //StrategyP stp = new StrategyP(stf.DellStrategy()); //stp.Name = "Error Strategy"; //stp.DellDescription(); //分步策略,使用了2种策略StrategyFactory和StrategyPC,各基类分别独立封装 StrategyFactory sf = new StrategyFactory(new DellFactory()); //通过Dell工厂调用 StrategyPC sp = new StrategyPC(new Dell("Dell")); //暴露了具体实现的Dell类 sp.Name = "Dell-Strategy"; sp.Describe(); sf = new StrategyFactory(new IBMFactory()); //通过IBM工厂调用 sp = new StrategyPC(sf.Create()); //没有暴露具体实现的IBM类,此处其实是把new IBM("")转变成了sf.Create() sp.Name = "IBM-Strategy"; sp.Describe();
运行结果
I am Dell-Strategy personal computer
I am IBM-Strategy personal computer
请按任意键继续…
改进一下把二个策略合并
class StrategyMix //Factory and PC Mix c5f9 Strategy { Factory f; PC pc; public string Name { get { return pc.Name; } set { pc.Name = value; } } //public StrategyMix(Factory f,PC pc) public StrategyMix(Factory f) { //this.f = f; //pc = this.f.Create(); pc = (this.f = f).Create(); } public PC Create() { return f.Create(); //return pc = f.Create(); } public void Describe() { pc.Describe(); } }
调用方式
//混合策略StrategyMix(把Factory和PC基类封装在同一个策略中) StrategyMix sm = new StrategyMix(new DellFactory()); //仅仅使用Dell工厂 sm.Name = "Dell-StrategyMix"; sm.Describe(); StrategyMix sm2 = new StrategyMix(new IBMFactory()); //仅仅使用IBM工厂 sm2.Name = "IBM-StrategyMix"; sm2.Describe();
运行结果
I am Dell-StrategyMix personal computer
I am IBM-StrategyMix personal computer
请按任意键继续…
策略模式的优缺点
策略模式的主要优点有:
•策略类之间可以自由切换,由于策略类实现自同一个抽象,所以他们之间可以自由切换。
•易于扩展,增加一个新的策略对策略模式来说非常容易,基本上可以在不改变原有代码的基础上进行扩展。
•避免使用多重条件,如果不使用策略模式,对于所有的算法,必须使用条件语句进行连接,通过条件判断来决定使用哪一种算法,在上一篇文章中我们已经提到,使用多重条件判断是非常不容易维护的。
策略模式的缺点主要有两个:
•维护各个策略类会给开发带来额外开销,可能大家在这方面都有经验:一般来说,策略类的数量超过5个,就比较令人头疼了。
•必须对客户端(调用者)暴露所有的策略类,因为使用哪种策略是由客户端来决定的,因此,客户端应该知道有什么策略,并且了解各种策略之间的区别,否则,后果很严重。例如,有一个排序算法的策略模式,提供了快速排序、冒泡排序、选择排序这三种算法,客户端在使用这些算法之前,是不是先要明白这三种算法的适用情况?再比如,客户端要使用一个容器,有链表实现的,也有数组实现的,客户端是不是也要明白链表和数组有什么区别?就这一点来说是有悖于迪米特法则的。
版权所有,转载请注明文章出处 http://blog/csdn.net/cadenzasolo
相关文章推荐
- PropertyChangeListener简单理解
- 什么是设计模式
- 设计模式之创建型模式 - 特别的变量问题
- 七、设计模式——装饰模式
- 设计模式总结
- 设计模式之创建型模式
- 浅谈设计模式的学习
- PHP设计模式之装饰者模式代码实例
- php设计模式之单例模式实例分析
- 介绍php设计模式中的工厂模式
- PHP设计模式之适配器模式代码实例
- 深入浅出23种设计模式
- 浅谈c#设计模式之单一原则
- C#设计模式之观察者模式实例讲解
- C#设计模式之单例模式实例讲解
- 学习JavaScript设计模式(接口)
- 深入理解JavaScript系列(28):设计模式之工厂模式详解
- 面向对象设计模式的核心法则
- JavaScript设计模式之单件模式介绍
- 学习JavaScript设计模式之观察者模式