《深入浅出设计模式》读书笔记 C#版(第一章)
原始需求和设计
事情是这样开始的,公司需要做一套程序,鸭子,设计如下:
一个鸭子父类,多个派生类,三个可override的方法。
第一次需求变更
我们要会飞的鸭子!!!!!
所以我们做了如下的更改:
父类加了fly方法,嗯,所有的鸭子都会飞了,需求实现!
问题发生了,因为不是所有的鸭子都会飞
我们可以在派生类中把父类的fly方法中的内容覆盖掉,那么这个鸭子就不会飞了!
那么问题又来了,如果再出现几个新型鸭子都不会飞,是不是每个都得覆盖一遍fly方法啊????
也许,可以用接口?
把每个方法都做成接口,如图:
这是超笨的方法,如果一些鸭子的飞行方式发生变化,那么得改多少个类啊。。。
现在的情况是:
继承不行,因为鸭子的行为(需求)在子类里面不断变化,而使用接口又无法进行复用。
幸好,面向对象软件开发有这样一个原则:
找出应用中可能需要变化的地方,把它们独立起来,不要和那些不需要发生变化的代码混在一起。
这句话另一种思考方式就是:把变化的部分取出并封装起来,以便以后可以轻松的改动或扩展,而不影响其他部分。
所以我们应该把鸭子的行为都提取出来。
根据需求,我们知道鸭子的fly和quack行为经常发生变化,所以我们现在的设计是这样的:
设计原则:
针对接口编程而不是针对实现编程。
这是变化的部分,对于Fly和Quack分别定义接口。
namespace DesignPatterns.Intro.Bases { public interface IFlyBehavior { void Fly(); } } namespace DesignPatterns.Intro.Bases { public interface IQuackBehavior { void Quack(); } }
然后实现几种类型的Fly和Quack:
namespace DesignPatterns.Intro.Derives { public class Squeak: IQuackBehavior { public void Quack() { Console.WriteLine("吱吱"); } } } namespace DesignPatterns.Intro.Derives { public class NormalQuack: IQuackBehavior { public void Quack() { Console.WriteLine("呱呱"); } } } namespace DesignPatterns.Intro.Derives { public class MuteQuack: IQuackBehavior { public void Quack() { Console.WriteLine("---------"); } } }
整合鸭子的行为
让我们来定义鸭子:
namespace ConsoleApp2.Bases { public abstract class Duck { private readonly IFlyBehavior _flyBehavior; private readonly IQuackBehavior _quackBehavior; protected Duck(IFlyBehavior flyBehavior = null, IQuackBehavior quackBehavior = null) { _flyBehavior = flyBehavior ?? new FlyNoWay(); _quackBehavior = quackBehavior ?? new MuteQuack(); } public abstract void Display(); public void PerformFly() { _flyBehavior.Fly(); } public void PerformQuack() { _quackBehavior.Quack(); } public void Swim() { Console.WriteLine("所有的鸭子都会游泳"); } } }
这是鸭子的抽象类。
建立实际的鸭子:
namespace ConsoleApp2.Derives { public class MallardDuck: Duck { public MallardDuck(IFlyBehavior flyBehavior = null, IQuackBehavior quackBehavior = null) : base(flyBehavior, quackBehavior) { } public override void Display() { Console.WriteLine("我是个野鸭..."); } } }
测试鸭子
namespace ConsoleApp2 { class Program { static void Main(string[] args) { var duck = new MallardDuck(new FlyNoWay(), new NormalQuack()); duck.PerformFly(); duck.PerformQuack(); duck.Display(); Console.ReadLine(); } } }
这时,需求终于完成了!
我们的鸭子根据传入的Fly和Quack实现类不同而具有不同的效果!
需求又变了,要求鸭子的行为可以随时改变
这时,我们需要动态设定行为,我们只需要加入Set方法即可:
Duck最新的代码是:
namespace ConsoleApp2.Bases { public abstract class Duck { public IFlyBehavior FlyBehavior { private get; set; } public IQuackBehavior QuackBehavior { private get; set; } protected Duck(IFlyBehavior flyBehavior = null, IQuackBehavior quackBehavior = null) { FlyBehavior = flyBehavior ?? new FlyNoWay(); QuackBehavior = quackBehavior ?? new MuteQuack(); } public abstract void Display(); public void PerformFly() { FlyBehavior.Fly(); } public void PerformQuack() { QuackBehavior.Quack(); } public void Swim() { Console.WriteLine("所有的鸭子都会游泳"); } } }
测试效果:
namespace ConsoleApp2 { class Program { static void Main(string[] args) { var duck = new MallardDuck(); duck.PerformFly(); duck.PerformQuack(); duck.Display(); duck.FlyBehavior = new FlyWithWings(); duck.QuackBehavior = new Squeak(); duck.PerformFly(); duck.PerformQuack(); Console.ReadLine(); } } }
需求完成!!!
最终结构如下:
设计原则:多用组合,少用继承
《深入浅出设计模式》读书笔记 C#版(第一章)的更多相关文章
- 读书笔记http之第一章
http TCP/IP协议各层: 应用层 决定了向用户提供应用服务时通信的活动. 比如 : FTP(FileTransferProtocol,文件传输协议)和DNS(DomainNameSystem, ...
- 深入浅出Nodejs读书笔记
深入浅出Nodejs读书笔记 转:http://tw93.github.io/2015-03-01/shen-ru-qian-chu-nodejs-reading-mind-map.html cate ...
- SQL Server2012 T-SQL基础教程--读书笔记(8 - 10章)
SQL Server2012 T-SQL基础教程--读书笔记(8 - 10章) 示例数据库:点我 CHAPTER 08 数据修改 8.1 插入数据 8.1.1 INSERT VALUES 语句 8.1 ...
- 《Android开发艺术探索》读书笔记 (3) 第3章 View的事件体系
本节和<Android群英传>中的第五章Scroll分析有关系,建议先阅读该章的总结 第3章 View的事件体系 3.1 View基本知识 (1)view的层次结构:ViewGroup也是 ...
- 《Android开发艺术探索》读书笔记 (13) 第13章 综合技术、第14章 JNI和NDK编程、第15章 Android性能优化
第13章 综合技术 13.1 使用CrashHandler来获取应用的Crash信息 (1)应用发生Crash在所难免,但是如何采集crash信息以供后续开发处理这类问题呢?利用Thread类的set ...
- HeadFirst设计模式读书笔记--目录
HeadFirst设计模式读书笔记(1)-策略模式(Strategy Pattern) HeadFirst设计模式读书笔记(2)-观察者模式(Observer Pattern) HeadFirst设计 ...
- 高性能MySQL(第4版) 第一章 MySQL架构 读书笔记
这本书去年11月出的,今年中文版也出了,并且直接上了微信读书,之后有空就读一读,分享下读书笔记~ 原文内容比较充实,建议有时间可以读一下原文. 第一章主要是个概览. MySQL的逻辑架构 默认情况下, ...
- Java 线程第三版 第一章Thread导论、 第二章Thread的创建与管理读书笔记
第一章 Thread导论 为何要用Thread ? 非堵塞I/O I/O多路技术 轮询(polling) 信号 警告(Alarm)和定时器(Timer) 独立的任务(Ta ...
- Java 螺纹第三版 第一章Thread介绍、 第二章Thread创建和管理学习笔记
第一章 Thread导论 为何要用Thread ? 非堵塞I/O I/O多路技术 轮询(polling) 信号 警告(Alarm)和定时器(Timer) 独立的任务(Ta ...
- 《Android开发艺术探索》读书笔记 (9) 第9章 四大组件的工作过程
第9章 四大组件的工作过程 9.1 四大组件的运行状态 (1)四大组件中只有BroadcastReceiver既可以在AndroidManifest文件中注册,也可以在代码中注册,其他三个组件都必须在 ...
随机推荐
- spring mvc:ueditor跨域多图片上传失败解决方案
公司在开发一个后台系统时需要使用百度的UEditor富文本编辑器,应用的场景如下: UEditor的所有图片.js等静态资源在一个专有的静态服务器上: 图片上传在另外一台服务器上: 因为公司内部会使用 ...
- 前端面试angular 常问问题总结
1. angular的数据绑定采用什么机制?详述原理 angularjs的双向数据绑定,采用脏检查(dirty-checking)机制.ng只有在指定事件触发后,才进入 $digest cycle : ...
- 第1阶段——u-boot分析之make指令(2)
通过make 100ask24x0_config 指令配置好芯片选型后,使用make指令来生成uboot.bin文件 本文学习目标: 对Makefile文件进行基本了解,掌握make指令是怎么实现生成 ...
- 【C++小白成长撸】--N阶幻方(魔阵)矩阵
解决方法:1.第一个元素放在第一行中间一列 2.下一个元素存放在当前元素的上一行.下一列. 3.如果上一行.下一列已经有内容,则下一个元素的存放位置为当前列的下一行. 在找上一行.下一行或者下一列的时 ...
- this的用法 – JavaScript深入浅出(二)
写在前面 上一篇中,我们对于JavaScript中原始值.复杂值以及内存空间进行了一个深入浅出的总结,这次我们来聊一聊JavaScript中this关键字的深入浅出的用法. 在 JavaScript ...
- 构建具有用户身份认证的 React + Flux 应用程序
原文:Build a React + Flux App with User Authentication 译者:nzbin 译者的话:这是一篇内容详实的 React + Flux 教程,文章主要介绍了 ...
- VHDL学习:利用Quartus自带库3步快速完成状态机
Quartus自带库里面有各种编程语言的模板,供开发者参考. 初学者利用VHDL实现状态机比较生疏的情况下,可以调出该模板,适当修改即可. 本文将描述如何利用Quartus自带库调出状态机模板,并适当 ...
- java伪代码《大道至简》
阅读<大道至简>第一章,深感作者对编程问题的精炼定义,通过对古老寓言故事<愚公移山>的引用,说明了编程的本质,即顺序,分支,循环.其中又将他们扮演的项目组织者,团队经理,编程人 ...
- SGI STL内存配置器存在内存泄漏吗?
阅读了SGI的源码后对STL很是膜拜,很高质量的源码,从中学到了很多.温故而知新!下文中所有STL如无特殊说明均指SGI版本实现. STL 内存配置器 STL对内存管理最核心部分我觉得是其将C++对象 ...
- 结对编程四则运算gui
码市地址:https://git.coding.net/linzhao/sizeyunsuangui.git 林 钊 -- 201421123105 吴世荣 -- 201421123119 王坤彬 - ...