作为一个php开发者,深知曾经很多程序员都鄙视php,为什么呢?因为他们认为php的语法是dirty的,并且由于开发者水平参差不齐导致php的代码更加乱上加乱,维护起来简直一坨shit一样。随着php加入了面向对象的阵型之后,很多开发者开始使用了oop思想来写代码,php也变得越来越标准,越来越规范。而其中,设计模式起到了不小的作用。最近老大找我谈话,说php这边的开发模块耦合度过高,代码感觉质量不高,想来一次代码重构行动。我对代码重构也是一知半解,而代码重构的基础就是去了解设计模式,于是我翻起了这本<<Head First 设计模式>>(经典书籍),开始学起了曾经认为没啥用的设计模式。
so,今天先来个开胃菜,写一个策略模式的简单笔记以及自己的理解先吧。
先来个官方解释吧: 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。简单的来说吧,其实就是相当一个可以随时切换的类来提供给客户端使用。可能这么说久更抽象了,不要紧,就从例子慢慢来吧。
其实说白了,策略模式可以说是类的一种行为。我们如果有过YII或者其他PHP框架的开发经验,我们可以了解到,这些框架都为我们提供了一个行为机制。何为行为?行为就是一个类可以随时拥有,可以随时删除和改变的东西。如同人的行为,我们的行为可以有打架、吃饭、讨论、跳广场舞,正常来说,这些行为我们并非天生俱来的,而是从外部获得的。反之,类的也是这样。那你可以说,我可以是天生的啊,我继承我的父母祖辈不可以么?好吧,满足你的心愿,我们就先看看继承吧,上代码:
// 父亲 class Father { public function eat() {} public function dance() {} public function sayMyName() {} } // 儿子1 小明 class Xiaoming { public function eat() { echo '喜欢吃西红柿炒鸡蛋'; } public function dance() { echo '喜欢跳爵士舞'; } public function sayMyName() { echo '小明'; } } // 儿子2 小萌 class Xiaomeng { public function eat() { echo '喜欢吃土豆炒肉'; } // 抱歉,我不喜欢跳舞 // public function dance() { // echo '喜欢跳爵士舞'; // } public function sayMyName() { echo '小萌'; } } $xiaoming = new Xiaoming(); $xiaomeng = new Xiaomeng(); $xiaoming->eat(); $xiaoming->dance(); $xiaomeng->eat(); $xiaoming->dance(); // 我明明不喜欢跳舞,还是会跳舞
可以明显看到继承的一个缺点就是,有些方法会强行“塞到”一个类之中,这样是不灵活,不健壮的,而且假如有一天小明突然喜欢吃“回锅肉”了,那岂不是又得改动小明类的eat方法,就不能动态去修改?
这个时候,以“组合为先”的策略模式就可以出手了,这个时候我们先写一个EatBehavior和DanceBehavior接口,代码如下:
interface EatBehavior { public function eat(); } interface DanceBehavior() { public function dance(); }
然后,针对这个吃的和跳舞的行为接口,我们去做一系列不同的吃的和跳舞的行为类,代码如下:
class EatXiHongshiBehavior implements EatBehavior { public function eat() { echo '西红柿炒鸡蛋'; } } class EatTuDouBehavior implements EatBehavior { public function eat() { echo '土豆肉片'; } } class JuqShiBehavior implements DanceBehavior { public function dance() { echo '爵士舞'; } } class JieWuBehavior implements DanceBehavior { public function dance() { echo '街舞'; } }
可以看到,我们这里有两个Eat行为和两个Dance行为,这时候,我们就可以去掉Father类的eat()和dance()了,此时,我们的父亲、小明、小萌这三个类就简化成这样了:
// 父亲 class Father { // public function eat() {} // public function dance() {} public function addEatBehavior(EatBehavior $eb) { $eb.eat(); } public function addDanceBehavior(DanceBehavior $db) { $db.dacne(); } public function sayMyName() {} } // 儿子1 小明 class Xiaoming { public function sayMyName() { echo '小明'; } } // 儿子2 小萌 class Xiaomeng { public function sayMyName() { echo '小萌'; } }
我们可以看到,我们的小萌已经不用强行集成跳舞行为了,而是可以有一个添加跳舞行为的方法,这样就自由多了!这个时候,如果我们想要小明学跳爵士舞的话,那么我们久用$xiaoming->addEatBehavior(new JuqShiBehavior()),想转行跳街舞的话我们就可以$xiaoming->addEatBehavior(new JieWuBehavior()),想学其他舞种的话就写多一个类继承DanceBehaivor接口就OK了!
这样做的好处就是灵活且能够动态切换组合类自身需要的功能,而不用硬继承父类的一切方法,细心的朋友发现addEatBehavior还是addDanceBehavior的参数类型都是一个接口类,这样做符合了设计模式的“为接口而编程,而非实现”的原则,这样我们就能多态的传入不同的吃的跳舞的行为类去让类获取这些功能了,这样随意组合拆分会让类和类更加松散。在框架中,我们利用行为就是等于使用了这种设计模式,所以在今后的开发中,我准备多去写写框架的行为类,然后把冗余重复的给提出成为行为,让不同的控制器随意组合,这样就能进一步解耦了。好了,这就是策略模式!