设计模式之策略模式

设计模式

最近买了本设计模式的书Header First 非常喜欢其中的讲解方式。虽然买了有一段时间了但是没有认真的看过。这段时间工作相对没有那么难了,所以抽出点时间看一下这本书,同时,在这里做一下分享,希望可以帮到你!

1、定义

策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户

2、使用场景

我们的日常开发中经常碰到一类问题,例如有一个类(Animals),他有几个方法(fly,eat),某一天我们需要创建一个对象1恰好是要有fly/eat这两个方法,后来我们又创建了另外的一个对象2有eat这个方法。这时候我们最容易想到的肯定是继承。但是如果有一天,我们要给对象1和对象2增加一个sleep方法,显然最简单的方法就是在Animals中加入一个方法sleep。

后来,产品有要求创建另外的一个对象拥有sleep和eat的对象3,很显然,我们仍然可以通过继承的方式,派生出一个Animals的子类。尽管没有要求对象3有fly这个方法,但是实际上这个方法已经从父类中继承了。

开始的时候,产品大大说这三个对象的eat方法是一样的,直接打印出一个吃就可以了,但是慢慢地,产品大大们发现,这三个对象不是一个品种呀,所以他们吃的东西肯定也是不一样的。因此他们的eat方法的实现是不一样的。

我的天呐,这可怎么办,我们之前是直接写在父类中的。所以,我们最直接的方法就是在Animals的所有子类中重写eat这个方法。甚至有些没有eat这个行为的对象,我们为了避免出现问题也实现了这个方法(方法中不做任何操作)。另一方面 这也在考验我们的记忆力,那些对象是继承自Animals的,哪些对象的eat方法对需要做什么。

这时候才发现:继承害人不浅啊!!!!

3、思考

1、以后,产品大大们脑洞大开,可能还会有很多新的对象要加入,他们的行为可能会更加的复杂,我们该如何做?

2、父类中的有些方法,并不是非要让所有的子类都去实现? 这可能造成大量的代码冗余

3、如果从代码复用的角度去考虑,如果哪天我们有一个Person类也需要调用eat这个方法,我们该如何复用

4、新人报道,他是如何知道父类中eat方法到底有多少种类型。挨个查找子类中的方法 Are you Kidding me?

5、如何去动态的改变子类中的这些方法,有一天 我想让他吃肉,第二天我又想让他吃素,怎么动态判断和修改

4、修改思路

考虑到代码的复用,我们最先想到的就是代码的隔离,上面我们采用的方法是面向方法的实现进行编程。子类实现了什么样的方法。我们在去做对应的操作,这就意味着,我们的操作具有了一个前提:我知道他要做什么了。这样就导致了我们的代码毫无复用性可言

从这一点考虑,我们首先想到了面向接口编程的方法:将具体的方法和对象隔离,简单点来说就是,如果你想要有eat的功能,那么你就遵守我eat这个协议,实现协议方法。这样就可以从一定程度上降低了对象和方法的耦合性,最起码这两者不再是绑定的关系了。

但是,仔细考虑一下,我们的代码复用性还是不高,如果我们两个对象要实现的功能是一模一样的,那岂不是我这两个对象同时都要遵守协议实现接口中的方法? 代码的复用性还是有待提高啊!

所以,我们考虑将方法的实现彻底的与使用这个方法的类分离开。这样才能进一步增加代码的复用性。同时实现了不同对象的隔离。

5、具体实现

首先我们从最上层考虑,对于这些对象,他们都有同一个父类(Animals),但是这里我们不在这个父类中声明或者实现任何关于eat/sleep/fly这些操作。对于这些动作,我们设置多个接口(这里使用eat举例)。考虑现存的eat方法有几种(eatvg,eatmeat),我们新建两个类分别为eatvg,eatmeat。这两个类遵守关于eat的协议并且实现eat协议中的eat方法。

通过上面这一步,我们基本可以把对象和方法做了彻底的分离,那么我们如何在对象中调用其所需要的方法呢?

1、在父类animals中声明一个变量,表明这个animals的eat方法

2、在初始化的时候 给父类中的这个方法赋值(eatvb或是eatmeat)

3、如果需要执行eat的方法可以直接调用初始化的时候给eat赋值的方法

这样我们通过属性的方式,做了绑定,在做到代码最大限度复用的情况下,解决了继承给我们带来的种种问题。

策略模式

代码放在这里了