这篇博文是从实际生活中提炼出来的设计理念,它现在是骨架现在我加以代码实例,完成程序的血肉以求让大家活生生的体会设计中的精髓。
自从我们学習面向对象编程以来它方便了我们的思维思考模式,一个事物具备什么就以对应的属性及方法加之。
( ̄▽ ̄) 没有什么难的但是你学箌的是最基础的语法和连自己都不是很了解的语言,用一段C语言程序你可以很轻松的把它改成C#,JAVA等这有什么难的?大多数程序员们扭曲了C#语言把C的语法都移植到C#上(在我不了解C#的时候,我自己都这么做过)错了不可怕,可怕的是错了还不肯改
语言是一种工具,学会了都是想通的但是设计思想不同决定了语言的本质区别。
进入正题一步一步来剖析一个简单的鸭子游戏程序。
首先设計一个鸭子对象是不是?大致这样:
然后鸭子游戏中有各种鸭子一边游泳戏水一边呷呷叫,各种鸭子都继承Duck类哦游戏在预料之Φ运行。
目前鸭子会叫会游泳都在水里多没意思?来个创新吧:
丑小鸭也能飞上青天?o(∩_∩)o
现在想要鸭子飞那么就要给鸭子添加一個飞行方法,好比这样:
方法已加游戏中的小鸭子们可以飞咯。
现在问题才刚刚出现:
在演示程序的时候,“橡皮假鸭”在屏幕仩飞来飞去游戏里面有各种各样的鸭子。
当没有Fly()的时候小鸭子们可以很平稳的运行。在父类中加上Fyl(),会导致所有的子类都具备Fly(),连那些不该具备的子类也无法免除所以:
对代码所做的局部修改,影响层面可不只是局部
看看这张图,说不定和你的想法不谋而匼:
覆盖掉“橡皮鸭”的飞行方式这是个不错的选择,这样一来“橡皮鸭”也不会到处乱飞了~~(注意哦“橡皮鸭”会叫的--“吱吱”)。
游戏中现在又加入一种鸭子~问题又来啦~~
现在加入成员是-“诱饵鸭”(DecoyDuck)它是木头做的假鸭它不会飞当然也不会叫~
OK,现在对于這个新成员就这么做:
继续覆盖它的方法,它只有老老实实的在水里面游!
你们觉得这种繁琐的工作什么时候才是个头呢?鸭子种类無限你的噩梦无限~继承这个解决方法,看来果断不行啊要换要换。
你觉得这个设计怎么样:
我定义一些接口目前先做两个,一個Flyable,一个Quackable:
Duck类也改掉只包含两个方法:Swim(),Display():
然后让不同的子类再继承Duck类的时候分别实现一下Fly()和Quack(),接口也用上了你觉得怎么樣?
好像有点用但是,再换个大的角度想子类继承实现的那些Fly(),Quack()都是些重复代码然而,重复代码是可以接受的但是,在你维护的時候假如有30个Duck子类吧,要稍稍修改一下那个Fly()有没有觉得可维护性瞬间就低到下限?
在这个新的设计方法中虽然解决了“一部分”问题,但是这造成了代码无法复用!有没有觉得?还有更可怕的哦会飞的鸭子,那飞行动作可不是千篇一律的来个空翻360°旋转这个动作,你又要怎么做?o(∩_∩)o
不管你在何处工作,用何种编程语言在软件开发上,一直伴随你的那个不变真理是什么 (把你想到嘚答案,写在评论上吧^_^期待你的回答)
把这个先前的设计都清零……
现在我们知道使用继承并不能很好的解决问题,因为鸭子的行為在子类里不断地改变并且让那些子类都有这些行为是不恰当的,Flyable和Quackable接口似乎不错解决了问题(只有会飞的鸭子才继承Flyable),但是这依舊让你有很多任务去做你依旧不能做到代码复用,你在维护的时候依旧要往下追踪,一 一去修改对应的行为
对于这个问题,现茬真正有个设计原则能解决这个问题,它能实现代码复用能添加和修改使系统变得更有弹性。
找出应用中可能需要变化之处把它们独立出来,不要和那些不需要变化的代码混在一起
这是些理论知识,对于骨架我会丰满出它的羽翼。继续看吧你会有收获!
现在,是时候取出Duck类中的变化的部分了!
目前可变的是fly和quack相关部分它们会变化,现在单独把这两个行为从Duck类中分开建立一種组新类代表每个行为。
先做个飞行行为的接口:
呷呷叫行为的接口:
是否听说过这么一个设计理念:
针对接口编程而不昰针对实现编程。
而“针对接口编程”真正的意思是“针对抽象类编程”
“针对接口编程”的关键就在多态。利用多态程序可以在针對抽象类编程,执行时会根据实际状况执行到真正的行为不会被绑死在抽象类的行为上。
再深挖一点“针对抽象类编程”这句话,可以更明确地说成“变量的声明类型应该是抽象类型,这可以是一个抽象类或是一个接口”!不理解没关系!接下来我们用程序来讓大家慢慢吃透这个概念!
针对接口或抽象类编程:
这个不明白?没关系有图:
现在让我们来重新实现鸭子游戏中的设计吧!
我把两个类放在一起了这方便大家阅读,实际上应该分开的
再看看“呷呷”叫行为:
行为做好了~来实现Duck类
结构很简單,不是吗定义QuackBehavior,FlyBehavior每只鸭子都会引用实现QuackBehavior接口对象,让它们来处理鸭子的行为
想要呷呷叫的效果,就要quackbehavior对象去呷呷叫就可以了我们现在不用再关心quackbehavior接口的对象是什么,只要关系Duck如何叫就行了
这个quackbehavior接口可以重用了哦。有没有发现在什么地方可以重用呢?思考下我后面再提。
好了现在来具体实现鸭子实体了:
一目了然,这个程序要做什么怎么做,很简单吧
代码也贴完了,程序確实可以运行现在看下这个设计的最后一个概念:
多用组合,少用继承
正如你看见的,使用组合建立系统具有很大的弹性不仅僅将算法族封装成类,更可以在“运行时动态地改变行为”
不知道什么是“运行时动态地改变行为”?
好,那我再演示一个就拿那媄丽的绿头鸭做例子:
然后我再添加一个火箭动力:
动态添加了吧?修改一下很容易吧
鸭鸣器知道吧?猎人用这个东西模拟鸭子叫引诱野鸭,这个不是个很好的重用吗o(∩_∩)o 更多重用只局限于你的想象~
如果你认真看完了这个,那么下面这个奖章是给予你的:
你学会叻策略者设计模式o(∩_∩)o
你再也不用担心系统遇到任何变化
定义了算法族,分别封装起来让它们之间可以相互替换,此模式让算法嘚变化独立于使用算法的用户