Head First Design Mode(2)-设计模式入门(策略模式)
该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动!
设计模式入门:
欢迎来到设计模式世界;
我们会看到设计模式的用途和优点,再看看关键的OO原则,通过实例来了解模式是如何运作的;
以往是代码复用,现在是经验复用;
模拟鸭子的应用:
Duck(鸭子)会Quark(呱呱叫)和 Swim(游泳);
我们定义超类Duck::quark();swim();dispaly();
外观display方法是一个抽象方法,因为每种鸭子的外观各有不同;
ADuck,BDuck子类型的鸭子实现了display()方法;共同继承自Duck类;
这是一种继承的方式,在学习Java时一定学习过类似的题目;
现在让鸭子能飞:
利用继承,我们在Duck类中添加fly()方法;
但是,很多“橡皮鸭子”飞来飞去,因为父类中的方法会被所有子类继承;
导致很多不适合’飞’行为的子类也具有了该行为;
当涉及“维护”时,为了“复用”(reuse)目的而使用继承,结局并不完美;
继承下的做法:
在橡皮鸭类中把fly()方法覆盖掉,让它什么都不做;
带来的问题是,其他类型的鸭子都会受到影响,你不得不为其他不会叫的鸭子类重写fly()方法;
而当加入新鸭子时,由不得不检查这些方法;
我们不想代码在多个子类中重复,又很难知道鸭子的全部行为,最重要的,这样修改 会导致 牵一发而动全身,这显然不是我们想要的;
利用接口:
需要一个清晰的方法,让某些鸭子类型可飞或可叫;
我们把fly()和quark()分别声明在接口Flyable和Quarkable中,需要飞的鸭子实现相应的接口即可;
但这个设计真的好吗,这是一个多对多的关系,如果有20种鸭子,他们的飞行行为需要调整,那简直就是灾难;
我们看到:
继承并不是适当的解决方式;
接口解决了一部分问题,但是代码却没法有效的复用;
采用良好的OO软件设计原则:
软件开发的不变真理就是变化——不管当初软件设计的多好,一段时间后,总要成长与改变;
把问题归零:
我们知道了使用继承并不能很好的解决问题,因为鸭子的行为在子类里不断的变化,让所有的子类都有这些行为是不恰当的;
使用接口虽然解决了一部分问题,但是接口只有声明不具有实现的代码,所以实现接口无法达到代码复用;
适应此情况的设计原则:
找到应用中变化之处,独立出来,不要和不需要变化的代码混在一起;
变化的代码进行封装,使代码变化引起的后果变小,系统变得更有弹性;
该原则的另一种思考方式:
把会变化的部分取出来并封装起来,以便以后轻易地改动或扩充此部分,而不影响不需要变化的其他部分;
这几乎是所有设计模式背后的精神所在“系统中的某部分改变不会影响其他部分”;
分开变化的 和 不变的:
新建两组类与Duck无关的,一组是fly相关,一组是quark相关,每组类将实现各自的动作(高飞类、底飞类,咕咕叫类、嘎嘎叫类…);
这样取出来的一组fly相关类,就可以用来表示Duck的fly行为,一个鸭子可以有多种行为;
设计鸭子的行为:
一切能有弹性;比如,新建一个绿头鸭,初始的飞行行为是高飞,在运行过程中,我们可以动态的改变成底飞;
第二个设计原则:
针对接口编程,而不是针对实现编程;
比如fly行为被放在多个分开的类中,而这些类专门提供fly行为接口的实现;
这样鸭子类就不再需要知道行为的实现细节;
我们用接口代表了行为:FlyBehavior、QuarkBehavior;
由具体的行为类而不是Duck类来实现行为接口;
以往是行为来自超类的具体实现,或继承某个接口由子类自行实现而来;这两种做法都依赖于实现,没办法改变行为;
“针对接口编程”真正的意思是“针对超类型编程”:
因为所有实现接口的类,其接口类型,都可以看作是实现类的超类(或父类);
由于实现了相同的接口,他们就是相同的类型了,变量声明类型都是超类型;
这利用了多态,执行时会根据实际状况执行真正的行为;
超类型,通常是一个抽象类或一个接口;
如此,只要是具体实现此超类型的类所产生的对象,都可以指定给这个变量;这意味着,声明类时不用理会以后执行时的真正对象类型;
针对实现编程:
Dog dog1 = new Dog();dog1.bark();
针对接口编程:
Animal animal = new Dog();animal.makeSound();
而且,子类实例化执行的new动作不再需要在代码中硬编码,实际的子类型是什么不一定要知道,我们只关心他是否能正确的执行相应的动作;
实现鸭子的行为:
FlyBehavior-interface: fly();
FlyHigh: :fly();
FlyLow: :fly();
QuarkBehavior: quark();
QuarkGugu: :quark();
QuarkGuagua: :quark();
这样的设计这些行为被其他代码复用,因为它们已经和鸭子无关了;
整合鸭子的行为:
鸭子现在将飞和叫的动作“委托”给了其他对象处理,而不是用Duck类的叫和飞;
1)在Duck类中加入两个实例变量,均声明为接口类型;
2)使用performFly()和performQuark()方法,其中通过实例变量调用fly()和quark();
鸭子对象不亲自处理叫和飞的行为,而是委托给两个实例变量对象;
3)新建鸭子DuckSub1,在初始化方法中为实例变量赋值:高飞 咕咕叫!(实例变量是从父类继承来的)
编译运行下:
bogon:第一章 huaqiang$ javac *.java
bogon:第一章 huaqiang$ java DuckDrive
Fly high !
Quark gugu !
DuckSub1!
由于实例变量是接口类型的,我们也可以为它指定相同接口不同的实现类;
动态设定行为:
加入如下两个方法;
public void setFlyBehavior(FlyBehavior fb){flyBehavior = fb;
}public void setQuarkBehavior(QuarkBehavior qb){quarkBehavior = qb;
}
这样,就可以把 新的行为实现设定给指定的鸭子;
封装行为的大局观:
稍稍改变描述的方式,我们把一组行为,描述为一族算法;
那么,算法就表示鸭子能做的事,类似的场景:用一群算法计算某城市的销售税金;
封装飞行行为(各种飞行方式):一族算法;
……
我们发现同一族里的算法是可以互换的;
在上述示例中一定要明确几种关系:IS-A、HAS-A、IMPLEMENTS;
有一个的关系可能比是一个更好:
每个鸭子有一个FlyBehavior和QuarkBehavior,好将飞和叫 委托给他们代为处理;
这里将两个行为类 进行了 “组合”;鸭子的行为不是继承来的,而是适当行为对象组合来的;
第三个设计原则:
多用组合,少用继承;
实用组合将算法族封装成类,在符合正确的接口标准时,建立的系统也很有弹性;
此间,我们用了学到的第一个设计模式:策略模式;
策略模式:
定义了算法族,分别封装起来,让他们之间互相替换,此模式让算法的变化独立于使用算法的客户;
如何使用设计模式:
我们开发需要使用别人设计好的库和框架;我们挑选好组件,把他们放到合适的地方;
但是,库和框架无法帮助我们将应用组织成容易了解、容易维护、具有弹性的架构,所以需要设计模式,并在合适的场景中使用之;
设计模式告诉我们如何组织类和对象已解决某种问题;
有很多面向对象的原则,使用所有模式,当没有找到合适的设计模式时,遵循这些原则即可,下一章我们继续学习;
总结:
1.知道OO基础,不足以设计出良好的OO系统;
2.良好的OO设计必须具备 复用 可扩充 可维护三个特性;
3.模式可以让我们建造出具有良好OO设计质量的系统;
4.模式被认为是经历验证的OO设计经验;
5.模式不是代码,而是针对设计问题的通用解决方案;
6.大多数模式和原则,都着眼于软件变化的主题;
7.我们常把系统中会变化的部分抽出来封装;
8.模式让开发人员之间有共享的语言,能够最大化沟通的价值;
OO基础:
抽象 封装 多态 继承;
OO原则:
封装变化
多用组合,少用继承
针对接口编程,不针对实现编程;
OO模式:
策略模式:定义算法族,分别封装起来,让他们之间互相替换,此模式让算法的变化独立于使用算法的客户;
Head First Design Mode(2)-设计模式入门(策略模式)相关推荐
- 换个姿势学设计模式:策略模式
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源:公众号「闻人的技术博客」 前言 前段时间,接到一个 ...
- Java设计模式之策略模式与状态模式
一.策略模式定义 定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们之间可以相互替换,策略模式可以在不影响客户端的情况下发生变化. 好了,定义看看就完了,我知道你很烦看定义. 二.策 ...
- 研磨设计模式之 策略模式--转
http://www.uml.org.cn/sjms/201009092.asp 研磨设计模式之 策略模式 2010-09-09 作者:云飞龙行 来源:云飞龙行的blog 先感谢众多朋友的支持 ...
- 设计模式:策略模式(Strategy)
定 义:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化, 不会影响到使用算法的客户. 示例:商场收银系统,实现正常收费.满300返100.打8折.......等不同收费 ...
- C++设计模式之策略模式(Strategy)
Strategy策略模式 作用:定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户. UML图: 代码实现 #include <iostream& ...
- python策略模式包含角色_详解Python设计模式之策略模式
虽然设计模式与语言无关,但这并不意味着每一个模式都能在每一门语言中使用.<设计模式:可复用面向对象软件的基础>一书中有 23 个模式,其中有 16 个在动态语言中"不见了,或者简 ...
- 一篇博客读懂设计模式之-----策略模式
设计模式之策略模式 在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的对象 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换. 主要解决:在有多种算法相似的情况下 ...
- 面向对象设计模式之策略模式
面向对象设计模式之策略模式 1.策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户 2.抽象鸭子类,鸭子飞行行为在此处类似于算法族 1 package ...
- java策略模式详解_Java经典设计模式之策略模式原理与用法详解
本文实例讲述了Java经典设计模式之策略模式.分享给大家供大家参考,具体如下: 策略模式指:策略模式指将程序中可变部分抽象分离成一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式 ...
最新文章
- php 正则中文匹配
- 第三篇:时间和全局状态(三)
- python工资条教程_python学习笔记--工资条发放软件
- conda的导入导出
- ext2文件系统 - mke2fs
- 利用CSS让元素垂直居中的两种实现方法
- 算法代码块总结(持续更新)
- Activiti源码之建造者模式 Builder
- 解决 -- 代码没有问题时接口报错:Status Code: 404 Not Found
- php fckeditor demo,如何使用PHP添加fckeditor
- 【离散数学】命题逻辑符号化例题
- 开机直接进入键盘布局_屏幕虚拟键盘的使用
- jdk的selector(1)
- OpenGL ES总结(四)OpenGL 渲染视频画面
- 分享一款思维导图工具-幕布(附在线工具合集、Android进阶知识体系)
- ubuntu linux修改ip地址命令,如何在ubuntu桌面通过命令行,更改ip地址
- (一)Activiti 数据库25张表——一般数据1 (ACT_GE_BYTEARRAY)
- 数据分析 - 美国金融科技公司Prosper的风险评分分析
- 雨听 | 网页数据修改
- SetFocus()函数
热门文章
- 什么是跨域?浏览器为何禁止跨越请求?如何解决浏览器跨越问题
- Java中的浮点型数据类型
- PyQt5实战之二维码生成器(一):基本界面设计
- 光伏电站运维管理方案
- php htmlpurifier,php – HtmlPurifier – 允许数据属性
- 【饮食的迷思--人类必看的真正的饮食长寿指南--来自英国国王学院顶级遗传性流行病教授】---智人必须会的生活技能 by Tim Spector--饮食的迷思
- 京东“加关注”代码“ID必须以zx开头”的解决方法
- OpenCV:03图像的算数运算
- mybatis+spring+springmvc ssm整合
- PPT打开显示找不到 ppcore.dll,无法打开 PPT