《深入浅出设计模式》读书笔记 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文件中注册,也可以在代码中注册,其他三个组件都必须在 ...
随机推荐
- mysql存储过程 基本语法
话不多说 一.MySQL 创建存储过程 "pr_add" 是个简单的 MySQL 存储过程,这个存储过程有两个 int 类型的输入参数 "a"."b& ...
- CDN架构以及原理分析
详见: http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp61 在不同地域的用户访问网站的响应速度存在差异,为了提高用户访问的响应 ...
- !JS实战之随机像素图
JavaScript实例分享之----画随机像素图.随机像素图(作者自己取得名字)指的是一张图片上每一个像素的颜色都是随机的.此时应该能联想到这幅图多么眼花缭乱,好吧,我们用JS来实现它的原因是JS很 ...
- 团队作业4——第一次项目冲刺(Alpha版本)2017.4.22
昨天来不及编写,这是4月22日的日志,现在补上. 1.开完站立式会议后的合照 2.任务分解图 3.开会讨论的结果,任务分派 队员 今日进展 明日安排 陈鑫龙 原型设计图分析,设计登陆界面原稿 实现登陆 ...
- 201521123067 《Java程序设计》第8周学习总结
201521123067 <Java程序设计>第8周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 2. 书面作业 Q1.List中指定 ...
- 201521123099 《Java程序设计》第6周学习总结
1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...
- 201521123072《java程序设计》第四次总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.11.2 使用常规方法总结其他上课内容 一些小的方法归纳: 通过 instanceof 可以判断父类引用所引用的对象实例的实际类 ...
- 201521123118《java程序与设计》第9周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 1. 常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己以前编写的代码中经常出 ...
- 三分钟深入TT猫之故障转移
结束了一周繁忙的工作,趁着周末,小编手中的键盘早已饥渴难耐了,想知道上期省略号中发生了什么有趣的故事么?且听小编娓娓道来,结尾有彩蛋. 目录 风月前场 梦回现实 模拟老鸨 会话机制 故障转移 总结 风 ...
- request.getParameter()获取URL中文参数乱码的解决办法
这个问题耽误好长时间,URL传中文参数出现乱码,就算首次使用request接收就添加 request.setCharacterEncoding("UTf-8"); 依然报错不误. ...