博文更新啦。这2天学了一招分享出来,这招式如同 习武之人领悟了上层心法般。
今天说的是设计模式中经常用到的“策略模式”,概念不说,也不想说,什么是概念,概念就是 让大家理解这个东西是什么意思,可是对于编程理论介绍往往没有实践来的一针见血。
请耐心听完我说的话,很多朋友以为OOP就是理解了 继承 多态 封装 就够了,对,我承认这些是需要掌握,但是这是理论,这些理论的本质也需要掌握,比如:很多朋友以为 class A:class B,哇,这就是继承,可是 这个是继承吗?继承的本质是啥?继承的优势是什么?继承带来了什么好处?
就这个问题,我简单介绍下:
继承本质:你要从 内存机制下手,CLR的托管堆中的GC堆和LOAD堆下手,比如父类的字段在什么位置,比如方法表在什么位置,比如在调用方法的时候是调用什么父类的方法还是子类的方法,这些就是本质?
我写过一篇博文,对于这个本质说了一点:http://www.cnblogs.com/IAmBetter/archive/2012/02/22/2363485.html
可是,这是OOP吗,我说了这么一大堆,这些学完了是OOP吗,显然不是?
例子开始:
abstract class Dog { /// <summary> /// 一些狗公有的特性,跑,啃骨头就省略了 /// </summary> public abstract void Singing(); } class RedDog : Dog { public override void Singing() { Console.WriteLine("我是红狗,我会汪汪汪汪叫。。。"); } } class BlackDog : Dog { public override void Singing() { Console.WriteLine("我是黑狗,我会哇哇哇哇叫。。。"); } } class PcDog : Dog { //可是机器狗不会叫,也继承了怎么办? }
提示:对,我承认,你利用了 继承 多态 这2个OOP的思想,而且自以为用的还很好,可是问题来了,机器狗不会叫啊,但是也继承了Singing的方法必须实现这个抽象方法,怎么办?
很多朋友遇到了就会把这个 Singing方法抽象出来,比如抽象成一个接口,然后会叫的狗就实现这个接口。好嘞,修改代码。
interface ISinging { void Singing(); } abstract class Dog { /// <summary> /// 一些狗公有的特性,跑,啃骨头就省略了 /// </summary> } class RedDog : Dog,ISinging { public void Singing() { Console.WriteLine("我是红狗,我会汪汪汪汪叫。。。"); } } class BlackDog : Dog,ISinging { public void Singing() { Console.WriteLine("我是黑狗,我会哇哇哇哇叫。。。"); } } class PcDog : Dog { //机器狗不会叫,那么我就不实现接口 }
哇,多完美,我用了接口实现了OOP的设计,可是问题来了?如果今天,我开心,我赋予 所有的狗要回飞,于是你又实现了 一个“IFly”的接口。哪天,我要让狗会跳舞,我还得实现“IDance”接口,依次下去。。。。
看代码:
interface ISinging { void Singing(); } interface IFly { void Fly(); } abstract class Dog { /// <summary> /// 一些狗公有的特性,跑,啃骨头就省略了 /// </summary> } class RedDog : Dog,ISinging,IFly { public void Singing() { Console.WriteLine("我是红狗,我会汪汪汪汪叫。。。"); } public void Fly() { Console.WriteLine("我会飞"); } } class BlackDog : Dog,ISinging,IFly { public void Singing() { Console.WriteLine("我是黑狗,我会哇哇哇哇叫。。。"); } public void Fly() { Console.WriteLine("我会飞"); } } class PcDog : Dog,IFly { //机器狗不会叫,那么我就不实现接口 public void Fly() { Console.WriteLine("我会飞"); } }
对,我承认,你利用了接口是完成了客户的需求,可是如果客户是个变态,他需要100000种狗,那么你这个 Fly方法必须写100000次,好庞大的代码量。
对了,我们说过OOP实现了代码复用,为什么不考虑下能否代码复用呢?
very good 策略模式的本质出现了:把所有的方法抽象出来,类似于你的接口,然后利用复用代码的特点,节省开发,灵活改变。
有点领悟没?就是说,你的接口实现,比如一个需求来了,你是为了 完成这个需求(设计)而写代码,这是解决方法,不是思想,而OOP思想是为了 接口编程,为了N多设计,为了N多需求,从一定的高度思考设计框架的一个过程。
不说废话,开始写:
思考下:
狗Singing()方法是吧,如果有2种叫法,一种 哇哇叫,一种汪汪叫,那就抽象出来
狗还会飞()方法,比如会 低空飞,高空飞。
把这些会改变的动作抽象出来,把那些不会改变的动作封装起来,一起继承。
/// <summary> /// 这是所有Sing的叫法 /// </summary> interface ISingable { void Singing(); } class WAWA_Sing:ISingable { public void Singing() { Console.WriteLine("我会哇哇叫。。。"); } } class wangwang_Sing : ISingable { public void Singing() { Console.WriteLine("我会汪汪叫。。。"); } } /// <summary> /// 这是所有Fly的飞法 /// </summary> /// interface IFlyable { void Fly(); } class L_Fly:IFlyable { public void Fly() { Console.WriteLine("我会低空飞行"); } } class H_Fly : IFlyable { public void Fly() { Console.WriteLine("我会高空飞行"); } } abstract class Dog { /// <summary> /// 一些狗公有的特性,跑,啃骨头,是公有的特性不会改变,所以封装起来被继承 /// </summary> /// protected ISingable isingable; protected IFlyable iflyable; public void PerformSing() { isingable.Singing(); } public void PerformFly() { iflyable.Fly(); } } class RedDog : Dog { public RedDog() { isingable = new WAWA_Sing(); iflyable = new H_Fly(); } } class BlackDog : Dog { public BlackDog() { isingable = new wangwang_Sing(); iflyable = new L_Fly(); } }
代码如上:
1.当还有900个不同的狗 要设计的时候,如何飞,如何叫,只要在这个狗的构造函数内 声明下 是什么叫法类型的对象,是什么飞行类型的对象即可---实现了复用
2.对于如果没有会飞的狗或者不会叫的狗,必须在写代码前就考虑好。
这就是策略模式。
不妨大家可以尝试着,用这个模式 遇到什么设计都用这个模式,练习10几天,然后你自然会总结出 他的优势和缺点。