这是吐槽版的《什么是好莱坞原则》,移到垃圾桶。请参考什么是好莱坞法则(2016-06-25 12:42)
《编程导论(Java)·9.3.1回调》中,介绍了好莱坞法则/好莱坞原则(Hollywood principle),第287页。
- Hollywood principle:"Don't call me; I'll call you." (don't call us, we'll call you)
对于好莱坞原则的解释,在各种书籍、文献中极其混乱。本文介绍《编程导论(Java)》中对好莱坞原则的解释,以及为什么要这样解释。不可避免地,本文会把一些著名文献中的解释作为反面例子。
(重写 别了,DIP、IoC)
不懂递归,不要说学过算法;
不懂回调,不要说学过编程;
1.引子:多态
图1 依赖于抽象类型、针对接口编程、遵循OCP 代码的基本结构
Client中有方法test(),代码为:
IServer s = new Server();
s.foo(5);
对上述代码的解释:“s被初始化后,将按照s指向对象的实际类型(即Server),动态绑定foo()的代码块。”
这是面向对象中对于多态的基本解释方式(后面的讨论,将涉及到这一解释)。这里,yqj2065设定了一个前提:
我不喜欢对上述代码的其他云山雾绕的解释!
2.回调
回调与通常的非回调代码,从类图和其自身代码上,没有区别——都是调用下层模块的一个接口。非回调代码(如果不考虑OCP),如图1所示的Client,可以直接依赖于(具体类型)Server;而在图2所示的回调的应用场景中,上层的Client直接依赖于下层的Server,但是下层的Server不能够依赖Client,问题是:Server需要调用上层的Client的方法callback,怎么办?
因而不得不在下层(Server所在的层或更下层、或基础设施/框架中)定义一个Client的父类型,如接口IClient 或IXxx,结构如图3所示。
图3 回调的基本结构
- 【请比较图1和图3】回调与通常的非回调代码,从类图和其自身代码上,没有区别。
- (为了使用回调)回调机制不得不在下层(或基础设施/框架中)定义一个Client的父类型IClient或 IXxx,它定义了回调callback(int)的方法头(方法的接口)
- (Java中)回调与通常的(遵循OCP 代码的)非回调代码,使用的技术不过是动态绑定/多态。
3.我的好莱坞法则
4.类层次与好莱坞原则
Don’t call us, we’ll call you.
The parent class tells the child class the same thing.”
- 上文中的下划线部分本身就是错误的。画类层次时,可以说父类型是higher level components,蛋是,从依赖关系上看,按照分层和依赖的单向性,子类是上层模块、父类是下层模块(如果不在同一层的话)。例如父类是JDK或框架中的某个类,而子类是你的应用中的类。因为子类(必须的)依赖父类型,你不可能将父类型放在上层,而让下层(的子类)依赖于上层。
- 如“1.引子:多态”所言,有动态绑定,在类层次中使用回调、好莱坞原则的解释是一种极其无聊的解释,而且令人困惑。
- 按照他的说法,(不管他的like...)好莱坞原则“应该”意味着“上层调用下层而下层不得调用上层”;对啊,但是,而这一“上层调用下层而下层不得调用上层”,我们称之为单向依赖,不需要搞一个多此一举的“好莱坞原则”作为单向依赖的同义词。当然,如果上层模块说"Don't call me; I'll call you.",也非常符合该字面的解读,这种上层模块所说的好莱坞原则,和白开水一样,没有营养。
- 不管模板方法的细节,如“1.引子:多态”所言,s.foo(5)动态绑定,完全不需要”父类调用子类的操作“的说法。通常,父类不可能知道子类的附加的操作;对于override方法,那么s.foo(5)是Client调用IServer的foo然后IServer调用子类Server的overridr方法foo?
- [ S w e 8 5 ]的原文:Don't call us, we'll call you (Hollywood's Law): A tool should arrange for Tajo to notify it when the user wishes to communicate some event to the tool, rather than adopt an 'ask the user for a command and execute it' model.",和本文的【3.好莱坞法则】一致,而非【设计模式】的滥用。
- 按照面向对象的一般概念,子类是一个父类,父类动物有eat()方法,那么我们喂狗吃的时候即new Dog().eat(),有没有人说:”我喂动物吃,而动物调用狗的吃方法“,”我又喂动物吃,而动物调用猫的eat()方法“?太别扭了。
- 如果(类层次)低层模块=(分层结构)上层模块,(类层次)高层模块=(分层结构)下层模块,没有问题。
- 在分层结构中,上层依赖于下层,依赖必须是单向的。他的书中的图11.2除了看起来有点道理外,层次真的能够”倒置“吗?假设图11.2中的Utility是JDK或某个框架,你倒置给我看看。
- 他的书中的图11.2中的三个包,如果忽略policy、mechanism和Utility的寓意,从上到下事实上是Utility-mechanism-policy的普通结构,从结构上没有任何特别的地方;如果强调policy、mechanism和Utility的寓意,而且按照依赖的单向性,父类必须是下层模块,因而图11.2并无意义,实践中接口所有权倒置,其意义下图所示。通常将所谓的”policy server interface“等放入公共模块(而非好看地与Policy Layer放在一个包中)。总之,依赖关系没有变化,DIP的“倒置”没有什么营养。从软件开发管理的角度,DIP或许有启发意义,但是DIP既不是架构设计的原则,也不是面向对象类关系的设计原则。
- 接口所有权倒置,其意义如图3:
传统3层结构接口由BLL定义(所有权上移),但是BLL作为Mapper的下层模块。