用最简单的例子,从最简单的设计开始,重构着讲解设计原则与模式
提纲
开灯的例子选开灯做例子,是因为这个例子既常见又简单,而且潜在的需求多样。对于最简单的灯,从功能上讲,按下灯上的开关,灯就开了。 用代码实现这样一个有开关功能的灯,也是一件很容易的事情。 public class Light { void TurnOn() { Console.WriteLine("Light Turn On"); } void TurnOff() { Console.WriteLine("Light Turn Off"); } } 代码1 一个具有开关功能的灯就完成了。这个灯,功能完备、也满足当下的需求。一切美好。 直到有一天,有个客户说,灯上的开关坏了,能不能换一个?我才意识到这个灯的设计有问题——它的开关是换不了的。一面给用户解释,一面考虑着把灯和开关分开。 咱也是学过设计模式的人,知道要面向接口编程,绝不应该简单地把Light类拆解成Light和Switcher两个类。因为Switcher不应该依赖于具体实现,于是写出了下面的代码。 namespace Me.Lighting
interface ILightable { void ShowLight();
void HideLight();
} class Light : ILightable { void ShowLight() { Console.WriteLine("Light Turn On"); }
void HideLight() { Console.WriteLine("Light Turn Off"); }
} } namespace Me.Switch
{ using Me.Lighting; class Switcher public ILightable Light { get; set; } void TurnOn() { Light.ShowLight(); } void TurnOff() { Light.HideLight(); } } 代码 2 这个设计,不仅分离了灯和开关,甚至可以让这个开关灵活地控制要开关哪个灯。只要在开关前设置一下就可以,多方便。我自信满满地迁入了代码。 事实也证明这样的设计是成功的,产品的灵活设计得到了用户的认可,销量直线上升。 亲,请看下代码,在不使用什么别的设计模式的前提下,您觉得代码2有什么问题?无论是什么角度的都可以(当然,可能您的角度不是本文讨论的重点),最好先回复下留个底,别事后诸葛。 如果您一眼看到了问题,请直接阅读DIP那一节。 暗流涌动公司壮大之后 ,开始考虑向收音机行业进军。而且公司希望,这种灵活的设计可以沿用下去,收音机和灯的开关应该可以通用,对用户而言,都是拨那么一下。 我听到这个信息也是相当兴奋,但是当我开始着手写代码时,发现一些坏味道,开关依赖于ILightable 接口,那么我的收音机不得不写成这个样子才能与现有的开关兼容。 class Radio : ILightable { "Play radio"); } "Stop radio"); } } 代码3 虽然可以工作,但是这是严重的坏味道。因为如果有一天,灯的接口变化,我却要连收音机的代码一起改。这种情况绝不应该出现。且不用把LSP(Liskov替换原则)搬出来说教,很显然Radio其实并没有完成ILightable所定义的功能——发光。无论从哪个角度讲都是错的。 一个可行的设计是,让开关支持收音机的开启和停止。像下面这样。 namespace Me.Radio
interface IRadio void Play(); void Stop(); class Radio : IRadio void Play() { Console.WriteLine("Play radio"); }
void Stop() { Console.WriteLine("Stop radio"); }
using Me.Radio; class Switcher public ILightable Light { get; set; } public IRadio Radio { get; set; } void TurnOn() { if (Light != null) Light.ShowLight(); else if (Radio != null) Radio.Play(); } 代码4 |
- 解决$.ajax()请求异常~ jQuery提示parsererror错误解决办法
- vue todo-list组件发布到npm上的方法
- ruby-on-rails – 按关联对象的属性排序对象列表
- xml – 从Smartling下载所有文件的Curl
- xml – 在一个线性布局中居中一个按钮
- postgresql – postgres流复制 – 仅奴隶索引
- ruby – 嵌套,如果在.each迭代中
- 【APMCon 2016】云和恩墨创始人盖国强:Oracle数据库架构设
- oracle 报-ORA-00922: 选项缺失或无效 解决方法
- omn??iauth – 单一登录(facebook,twitter,linkedin)服务: