设计模式(一)设计模式入门之策略模式

最近在看“Head First 设计模式”这本书,有很多心得想写下来供自己以后阅读,也想分享给有兴趣的读者,大家可以一起来思考交流,学无止尽,希望我们共同努力。这本书主要是依据Java来讲的,如果你们没有学过Java也不要紧,这本书和语言无关,最主要的是思想。

其实之前也学习了解过很多设计模式,比如最常用的单例模式,享元模式,观察者模式等等,但是都没有认真的静下心来分享自己的心得,现在感觉非常懊恼啊,之前也因为工作太忙一直没有写新的文章,说白了都是懒惰惹的祸啊,现在来补上,以后会经常来更新文章的。。。加油!

这本书第一章主要以一个“鸭子”为例来引起读者的反思,这里简单阐述一下背景:
一个优秀的游戏开发程序员(Joe),参与了一个模拟鸭子的游戏项目,目前项目已经完成的差不多了。
这里阐述下大概逻辑:
在这里插入图片描述

第一次变化:
老板要求:这个时候,因为行业竞争压力大,老板想要创新,在股东会上展现出不一样的东西,要求Joe让鸭子会飞起来。
解决方案:Joe在鸭子的超父类(我一般喜欢理解为基类)里面加了一个方法fly(),然后实现了fly()的逻辑,果然非常快速的让所有鸭子都飞起来了。
如图:
在这里插入图片描述
结果如何:
果然老板在股东大会上看到了所有鸭子都在屏幕上飞来飞去,包括一只“橡皮鸭子”,惊呆了在场的所有人,老板感觉自己非常丢人,于是回来后生气的责备了Joe,于是Joe开始了新一轮的补救。

Joe发现利用继承来提供Duck的行为,这会导致很多问题:(这是书中的一道思考题)
1.代码会在多个子类中重复复用
(比如,会飞的逻辑,我们不能强行将飞的逻辑在基类实现,因为有些继承的子类鸭子不具有飞行的特性,如橡皮鸭子,所以我们就需要将飞行的逻辑放在子类去实现,可是又有很多子类对象有飞行的逻辑,这就会导致在很多的子类中我们会写大量重复相似的代码,如果后期修改优化飞的逻辑,改起来简直是恐怖。)

2.很难知道所有鸭子的全部行为
(比如,现在老板要求增加fly的行为,那么如果以后再增加别的行为怎么办,这无法估量。)

3.运行时的行为不容易改变
(例如我们现在让一只鸭子飞起来,但是在游戏运行过程中,只看鸭子飞吗,我们当然希望鸭子还有别的行为,那么如果这样的话,我们修改子类的鸭子的行为就会变得很不灵活,我们需要再去创建一个行为修改的方法,然后再去调控它的变化,每增加一个行为,我们都要去修改所有的子类去实现这个逻辑,这太可怕了)

4.改变会导致牵一发而动全身,还会造成其他鸭子不希望的改变
(这个同上,如果要修改鸭子的行为,不可能只修改一只,要改全部都会影响到,这不是我们希望的结果)

第二次变化:
那么接下来Joe思考了一下,要不然将 fly() 和 quack() 独立出来做成接口,然后让子类去实现接口?
结果:虽然解决了一些问题,但是还有一个严重的问题,代码会在多个子类中重复复用。

第三次变化:
这个时候Joe希望可以有一个设计模式帮助解决这个问题:
一个新的设计原则浮出水面:–> 一个新思路出现 “把问题归零” :我们在实际项目应用中找到可能需要变化的部分,将他们独立提取出来,“封装起来”,不要和那些不需要变化的逻辑放在一起,这样的话,无论你如何改变这些,都不会影响到其他的部分。

于是Joe将 fly() 和 quack() 提取出来,分别实现了一个飞行行为接口 和呱呱叫行为接口,然后各自创建具体的实现类,比如会飞的类,不会飞的类,会呱呱叫的类,会吱吱叫的类,不会叫的类等等,然后根据各自的子鸭子类的行为特性,分别将满足自己特性的行为类覆盖在各自的对象身上。
这样就将上述的所有问题都解决了,而且代码的拓展性增强。
在这里插入图片描述

Joe发现:以前的做法是在父类实现 fly(),子类继承优化, 或者是子类继承某个接口去实现具体功能,这些做法都太依赖于我们对需求的“实现”,我们被实现绑的死死的,从而导致拓展性严重受限,代码的灵活性大大降低。
于是又是一个新的设计原则浮出水面 --> “针对接口编程,而不是针对具体的实现去编程”

接下来我们在鸭子的基类中添加两个实例变量,
变量类型分别是FlyBehavior 和 QuackBehavior ,
添加两个方法 :performFly() 和 performQuack(),然后利用上面两个对象去各自调用自己的fly() 和 quack() 方法
同时去掉:基类的 fly() 和 quack() 方法
在这里插入图片描述

子类具体的调用实现:

public class MallardDuck extends Duck
{
	public MallardDuck()
	{
		quackBehavior = new Quack();
		flyBehavior = new FlyWithWings();
	}
	
	public void display()
	{
		System.out.println(" i am a real Mallard duck ");
	}
}

思考:虽然把行为设定为特定的行为类,通过引用变量去调用对应的行为,但是还可以再运行中轻易的修改它,因为quackBehavior 的变量是一个接口类型,所以我们可以在游戏运行的过程中动态的修改它,让它指向不同的QuackBehavior实现类。

备注:以上这种方式也不是最好的,在后面更多的模式中会去继续优化。

第四次变化:
这里还是有点问题,缺少动态设定行为的逻辑,于是我们需要增加动态设定行为:
Duck基类中新增两个动态设定飞行和呱呱叫的行为方法:
在这里插入图片描述

绿色的就是新增的两个方法,这样我们可以在游戏运行中动态的去修改鸭子的行为了!
于是又一个新的设计原则被我们发现了 —> “多用组合,少用继承”
思考:继承有继承的优点,其中一个优点就是可以让我们的代码复用,灵活变通,但是我们需要知道不仅继承可以做到,其他方式也一样可以达到这种效果。

整体分析:
我们在描述这块逻辑的时候,不再把鸭子的“行为” 说成“一组行为”,而是要把行为想象成“一族算法”,接下来这就是整个游戏项目的总览图。
在这里插入图片描述

模式大揭秘:
以上的实现逻辑的模式叫做 “策略模式”,它定义了算法族,分别封装起来让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

总结我们本章学习到的设计原则:
1.找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混合在一起;
2.针对接口编程,而不是针对实现编程;
3.多用组合,少用继承;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值