前言 今年的读书计划正式开张了,其实过年的时候就把书单中的《了不起的盖茨比》给阅读完了,但是看完如猪八戒吃人参果——不知啥滋味。只知道大概的故事情节,书中华丽的词藻、作品的艺术和主题并不能完全体会,更别说写一些阅读后的观感了。抽空肯定是要重新阅读几遍的,所以就不把它当作已读书籍了。
正式的阅读是从今天开始了,准备学习技术方面的书籍,但也先来点轻松的,就是这本《Head First 设计模式》。之前看过《Head First Java》书中内容通俗易懂,生动有趣是本入门的好书,设计模式呢是和那本书一起买的,买了也有些时候了,但是从学校到工作都是各种地方吃灰的角色,一直不能静下心来实践,感到十分羞愧。工作中也用到和阅读到各种设计模式却一直没有正确的认识,呈现在赶紧捡起来。
正文
设计模式是一种反复使用、多数人知晓、经过分类编目、代码设计的总结。它告诉我们如何组织类和对象以解决某种问题。而且采纳这些设计模式并使它们适合我们特定的应用,是我们责无旁贷的事。
设计原则 虽然之前并没有系统的学习设计模式,但对设计模式的六大设计原则还是略有耳闻的。不过本书目前不知道出于什么原因没有去介绍它,而是自己组织语言目前也就不得而知了,咱还是按书上的通俗易懂的先来。
找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
针对接口编程,而不是针对实现编程。
多用组合,少用继承。
实现策略模式 我们通过java
代码来实现策略模式。
现在公司有一种产品——Bird
(是的,你没看错,我们的产品就是鸟!),这只鸟目前的功能是walk()
和display
。我们还开设了两个子产品乌鸦和麻雀,如图:
1 2 3 4 5 6 graph TB; Bird["Bird<br> <br> <br>display()<br> <br>walk()"] Bird --> crow["crow<br> <br>display() //外观是黑色"] Bird --> sparrow["sparrow<br> <br>display() //外观是黄色"] style Bird fill:#FFFACD;
今年,公司的竞争压力加剧,公司主管认为是该创新的时候了,他们需要在下一次股东会议上展示一些”真正”让人印象深刻的东西来振奋人心了,于是我们决定让鸟能飞!
小明拍胸脯保证一周就可以完成,他想他只要在**Bird
类中加上fly()
方法,这样所有鸟类就都会飞了**:
1 2 3 4 5 graph TB; Bird["Bird<br> <br> <br>display()<br> <br>walk() <br> <br> fly() //👈小明加上的"] Bird --> crow["crow<br> <br>display() //外观是黑色"] Bird --> sparrow["sparrow<br> <br>display() //外观是黄色"] style Bird fill:#FFFACD;
小明觉得天衣无缝,但是在股东会议上的展示上主管发现有很多橡胶鸟也在飞,主管让小明尽快的解决问题,不然就准备去逛前程无忧吧。
小明觉得可以把橡胶鸟类中的fly()
方法覆盖掉,但是以后如果加入别的鸟类又会如何?再给鸟增加一个shout的功能呢?
利用继承来提供Bird
的行为,会导致:
代码在多个子类中重复。
很难知道所有鸟的全部行为。
改变会牵一发动全身,造成其他鸟不想要的改变。
运行时的行为不容易改变。
如果用接口呢?同样不行,使用接口会导致大量的重复代码,如果要稍微修改一下飞行的姿势那么每个鸟类的都要去处理。
这时候策略模式就上场了,策略模式的定义 :
1 策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立与使用算法的客户。
我们将fly()
和shout()
在Bird
中声明出来,并提供两个接口FlyBehavior
和ShoutBehavior
来实现这两个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public abstract class Bird { private FlyBehavior flyBehavior; private ShoutBehavior shoutBehavior; public abstract void display () ; public void flyPerform () { flyBehavior.fly(); } public void shoutPerform () { shoutBehavior.shout(); } public void setFlyBehavior (FlyBehavior flyBehavior) { this .flyBehavior = flyBehavior; } public void setShoutBehavior (ShoutBehavior shoutBehavior) { this .shoutBehavior = shoutBehavior; } public void walk () { System.err.println("I was walking..." ); } } public interface FlyBehavior { void fly () ; } public interface ShoutBehavior { void shout () ; }
你可能要骂娘了,这不还是使用接口吗,你丫逗我?放下手里的板凳别急。我们将鸟的行为以接口的形式声明在里面,而实现则放在分开的类中,此类专门提供某行为接口的实现,这样,鸟类就不再需要知道行为的实现细节了。
针对接口编程,关键就在于多态,程序可以针对超类型编程,执行时会根据实际状况执行到真正的行为,不会被绑死在超类型的行为上。
1 2 3 4 5 graph TB; Bird["FlyBehavior<br> <br> <br>fly()"] Bird --> Fly["Fly<br> <br>fly(){<br> <br> // I Can Fly<br>}"] Bird --> FlyNoWay["FlyNoWay<br> <br>fly(){<br> <br> //I Can`t Fly<br>}"] style Bird fill:#FFFACD;
FlyBehavior
和ShoutBehavior
的实现类我们很简单我们就只列举一个:
1 2 3 4 5 6 public class FlyNoWay implements FlyBehavior { @Override public void fly () { System.err.println("I Can`t Fly" ); } }
所有都完成后,我们增加一个产品喜鹊Magpie来测试我们模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Magpie extends Bird { public Magpie () { setFlyBehavior(new Fly ()); setShoutBehavior(new Shout ()); } @Override public void display () { System.err.println("I`m black" ); } }
我们指定了Margpie的fly()
和Shout
的实现类,然后我们让它飞起来:
1 2 3 4 5 6 7 8 9 public class Main { public static void main (String args[]) { Magpie magpie=new Magpie (); magpie.display(); magpie.flyPerform(); magpie.shoutPerform(); } }
输出为
1 2 3 I`m black I Can Fly G G G...
我们也可以调用seter
方法来动态改变鸟的行为。
1 2 magpie.setFlyBehavior(new FlyNoWay ()); magpie.flyPerform();
输出为:
1 2 3 4 I`m black I Can Fly G G G... I Can`t Fly
这就是策略模式,不要怀疑。多亏这个模式,小明可以勾画他的赌城狂欢之旅了。
现在回头看看整体的布局
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 graph TB; subgraph 封装飞行行为 FlyBehavior["FlyBehavior<br> <br> <br>fly()"] FlyBehavior --> Fly["Fly<br> <br>fly(){<br> <br> // I Can Fly<br>}"] FlyBehavior --> FlyNoWay["FlyNoWay<br> <br>fly(){<br> <br> //I Can`t Fly<br>}"] style FlyBehavior fill:#FFFACD; end subgraph 客户 Bird["Bird<br> <br> <br>display()<br> <br>walk() <br> <br> fly()"] Bird --> crow["crow<br> <br>display() //外观是黑色"] Bird --> sparrow["sparrow<br> <br>display() //外观是黄色"] style Bird fill:#FFFACD; end subgraph 封装叫喊行为 ShoutBehavior["ShoutBehavior<br> <br> <br>fly()"] ShoutBehavior --> Shout["Fly<br> <br>fly(){<br> <br> // I Can Fly<br>}"] ShoutBehavior --> NoShout["FlyNoWay<br> <br>fly(){<br> <br> //I Can`t Fly<br>}"] style ShoutBehavior fill:#FFFACD; end Bird --> FlyBehavior Bird --> ShoutBehavior