什么?!更改接口?
随着时间的流逝,市面上开始布满了使用tmfc的开关的产品,看着自己的产品受到大家如此热烈的欢迎,tmfc感到无比的满足。但是他还是发现有些产品没有使用他的开关,他感到纳闷,“为什么你们不在这个台灯上装开关呢?”他指着装有老式插口(可以把两根电线的其中一根更换插槽来实现不同功能的控制装置,在开关发明之前统治着这个紧耦合的世界)的台灯向厂家的促销员问道。“您有所不知啊!说起这个开关我还一肚子气呢!!我派人花重金到tmfc那里买了他那个该死的接口和开关,本想立上一大功的,没想到拿去向老板邀功时才发现根本用不上。因为我们的产品的特点就是有高亮和低亮两档可以调整,但是他那个要命的接口只有开和关两种,如果我们生产只能开关的灯,那根本就没有特色。您知道没有特色就没有竞争力。自从那之后我就被公司派到这个小地方来作促销员了。真是可恶,什么接口嘛,根本没用!!”那可怜的促销员咒骂着。tmfc暗自庆幸他没有亲自来买开关,不然现在被认出来肯定没好果子吃。他强作镇定,点点头快步走开了。
回到自己的工作室,tmfc反复想着这件事(其实在路上他也一直在想),当然,第一个念头就是“改接口”,这样的接口肯定可以满足他们的要求。
Interface IPowerSwitchable{
HighLight();
LowLight();
Off();
}
只要给他们这个接口和对应的开关就可以了嘛?没错,他们是可以满足,但是其他的需求呢,说不准什么时候就会出现可以调整高中低的台灯了。看来改接口不是好办法,tmfc想着其他的解决方案。
终极解决方案?
经过两个星期的苦思冥想,tmfc终于找到了终极的解决方案(其中的经过略去五万字)。他做出了一个可以拼接的开关,就像乐高玩具一样,用来把多个开关组合在一起。其中最重要的部分就是简化了接口,现在的接口看上去就像这样:
Interface ISwitchAction{
Execute();
}
而开关就变成了这样
class Switch{
ISwitchAction Action;
public void Switch(ISwitchAction action){
Action = action;
}
public void OnPress(){
Action.Execute();
}
}
“这样就可以满足所有的要求了!”,tmfc自言自语道。没错,只需要三个继承自ISwitchAction的类(HighLight,LowLight,OffLight),并分别使用他们来初始化三个开关,就可以满足台灯厂的要求了(虽然成本上会有一些小小的提高,但不会太多,因为开关和接口都做了简化)。
进一步的改进
“看上去还不错,但是能不能再做一点改进呢?”tmfc问自己。他拿着接口和开关反复翻看着,总觉得哪里还有些不对劲。“能不能把接口放在客户那里呢?不行不行,这明显是违反了DIP嘛!为什么非得用接口呢?把接口去掉能不能行得通呢?这样不是能够节省成本吗?”找到方向的tmfc顾不得两个星期奋战的疲惫,继续挑灯夜战。
又过了三个不眠之夜(大家可不要学tmfc,这对身体可是大大的有害啊),tmfc终于拿出了完善后的开关,这次没有接口了,但是多了一位新朋友:委托(delegate)。让我们先来认识一下这位朋友:
class delegate{
object Target;
MethodInfo Method;
delegate(object target,MethodInfo method){
Target = target;
Method = method;
}
Invoke(){
Method.CallOn(Target);
}
}
等等,好像又出现一个生面孔,MethodInfo,这是什么?由于tmfc不肯透露其中的奥秘(他声称这是技术机密),我们知道的只有这么多:只要调用MethodInfo.CallOn()方法,就可以在指定的对象(如台灯)上执行指定的命令(如HighLight)。(tmfc暗自偷笑:“其实没什么神秘的,就是记下了命令的位置,并在指定对象的相应位置加上电而已,一些简单的电路就能搞定。弄这个东西纯粹就是为了搞混大家,让我的发明显得高深莫测,哈哈。”)
松耦合的时代
tmfc在开关问世一周年的时候召开了全球开关用户大会,在大会上tmfc隆重的推出了他的改进型的开关,包括了各种通用的,专用的开关,以及各个合作厂商退出的诸如遥控器,键盘之类的相关产品,在全球引发了轰动。一个月后,tmfc的自传出版了,全世界的有志青年纷纷以这位年轻的传奇人物为榜样。若干年之后,各种新奇的发明(当然,都是受tmfc的开关的影响的)像插头插座,都极大的改变了人们的生活。从此,一个松耦合的时代来临了,而tmfc,也作为松耦合的创始人永远被这个世界的人们纪念着,在tmfc离开这个世界的那天,世界各国首脑商定将每年的12月4日(tmfc的生日)定为国际松耦合日。
故事背后的故事
- ISwitchAction是不是看着很眼熟,没错,这里使用了命令(Command)模式,ISwitchAction就是传统的ICommand接口,从其中派生的类就是一个个的命令(Command)。
- 委托和命令模式是不是有些相似?没错,委托其实比命令模式高明的有限。使用委托对于用户来说确实非常的方便(不需要自己继承命令接口,声明命令对象了)但是这个组合是有代价的。
- 委托的优势来源。委托将继承改成了组合,当然,这一步改进并不是那么容易的,在灵活性背后付出了性能的代价,当然这个性能代价对于不同的委托实现来说是不同的,像C++的函数指针就没有性能问题,而C#的委托则复杂的多(相应的灵活性也比函数指针要好,当然性能要差很多)
- 什么?按下一个开关打开所有的灯?当然可以,命令模式+组合模式都可以实现的东西怎么难得倒委托呢(丝毫没有看不起这两个模式的地方,事实上我非常的欣赏这种模式的组合)?只要扩展一下委托,在里面放一个MethodInfo的列表,在加上两个函数往列表里添加删除东西,Invoke的时候依次调用列表里的所有方法就OK了。
- 别被EventHandler搞混了。EventHandler也是委托,所以在.NET框架程序设计里讲事件的时候是没有用EventHandler关键字,而用了delegate关键字。倒是event关键字在幕后做了一些事情。