别了,DIP、IoC

[本文已经作为垃圾,请参考什么是好莱坞原则]

如果网上搜索依赖倒置原理/DIP、控制反转(IoC)容器等,会得到一大堆的信息,其中可能还包括yqj2065在本博客中发布的The Dependency Inversion Principle(翻译)(2005-01-28 00:22)的转载版(原文我也移到了垃圾桶)。

最近,在我系统地回顾设计模式时,感到应该与DIP、IoC说ByeBye了。

1、“依赖倒置”(1)这个名字令人不舒服,(2)当用“好莱坞法则”解释它时,显得不伦不类。(3)逻辑混乱,被我抛弃。

2、IoC,被玩坏了。

1.回调机制和好莱坞法则

  • 回调(call back,一个动词词组)机制,是一门编程语言,使得下层模块/库可以调用或执行上层模块定义的代码的机制。上层模块所定义的、被(下层模块)调用或动态绑定的代码,则被称为回调函数 (简称回调、callback,一个名词)。
  • 回调机制用于框架设计和通知机制。

通知机制中,如图9-11所示,上层模块Client调用了下层Server的copy()方法。假设上层需要更新进度条——显示复制任务完成的进度,显然上层并不清楚复制的进度而只有下层的Server才知道。这时下层模块如何将进度数据传递给上层的Client呢?
一种简单的方式:Server将进度数据保存在一个成员变量x中,并提供getX()。这样就需要Client时时刻刻地查询该数据。如同现实生活中打的士到某地,从上车的第一秒开始,时刻或每隔5秒问司机到了地方没有,也太烦人了。
另一种方式则是通知或使用回调。

2. 好莱坞法则:多个Client的对象或多个IXxx的其他实现类对下层Server2对象的某种状态变化感兴趣。以现实生活中的场景为例:一些男女演员们(Client)都对某导演(Server2)是否拍新片子感兴趣。导演肯定和的士司机一样,不喜欢演员们天天打电话询问。于是导演提供了一个让感兴趣的演员们留下电话号码的接口register(IXxx listener)。一旦导演准备拍摄一部新片子(sthHappened())就通知所有已登记的演员。而对于那些随时打电话询问是否有戏的演员,导演告诉他们一条好莱坞法则:"Don't call me; I'll call you."。

2.两个结构

这是OCP/抽象依赖原则的类图。

图1 抽象依赖原则

这是回调/好莱坞/观察者模式的类图:

图2 回调/好莱坞法则

 

两个结构完全相同的图,却有完全不同的含义/语义。

  • DIP的类图中,Client可以随时随地地调用Server,但是地主应该依赖于“I丫鬟”;
  • 回调/好莱坞/观察者模式的类图中,绝对不允许S依赖C。

用好莱坞法则、钩子解释OCP、DIP、模板方法显得异常地别致。

3.控制反转(IoC)

DIP的描述除了有点含糊,名字不好之外,可以作为OCP的操作性的注解。而控制反转(IoC)则是DIP缺点的继承者。

  • 对于图1,我不能够理解IoC的含义,地主依赖一个丫鬟,变成地主依赖一个I丫鬟,这时地主在编译时不依赖具体的丫鬟,但是地主还是依赖丫鬟。(注:有人用层次结构说明DIP的意义,有所谓真假DIP,等下在说。)

《设计模式》、和[3P•11DIP]中,出现了别致到别扭的好莱坞法则的解读。地主要I丫鬟上茶(),

I丫鬟 yh = new 丫鬟();  // I丫鬟 yh =(I丫鬟)getObject();

yh.上茶();

按照我们正常人的说法:yh按照引用的实际类型,动态绑定方法体。

看看别致的说法:地主要I丫鬟上茶,I丫鬟调用子类型丫鬟的上茶()。本来子类依赖于父类,这里父类可以调用子类型的方法,所以……父类依赖于子类??我不知道这里在说什么。

  • 《设计模式》:“模板方法导致一种反向的控制结构,这种结构有时被称为“好莱坞法则” ,即“别找我们,我们找你”[ S w e 8 5 ]。这指的是一个父类调用一个子类的操作,而不是相反。”
  • [3P•11DIP]:“This is sometimes known as the Hollywood principle..... The lower-level modules privide the implementation for interfaces that are declared within,andcalled by,the upper-level modules”

“反转”总不会是说父类依赖于子类吧?

  • 对于图2,也不知道哪里反转了。再说了,有回调或者观察者模式,这个含含糊糊的控制反转(IoC)纯属多余。

总之,IoC要么别扭,要么多余。

4.抽象依赖原则

 

一、在类设计层面,OCP、针对接口编程,或者我喜欢使用的“抽象依赖原则”(或许包括DIP)是同义词。OCP是目的/目标性的,针对接口编程,“抽象依赖原则”,DIP是操作性的。

但是DIP要改:

第一条: 地主 should not depend upon 丫鬟, both should depend upon I丫鬟。

第二条:不知道在类设计层面,这个Abstractions的意思。如果是指I丫鬟,这就是废话;如果是指Client?这就是梦话。ok,在类设计层面,这一条不要。

二、在架构设计或分层设计中,

上下层中添加一个服务层(接口层),可以看成DIP的应用,也是SOA的常用模式,【与《企业应用架构模式》中的Service Layer模式有些不同】。所以DIP-1挺好的。但是“倒置”,我随时不适应。依赖接口层的目的是封装变化,至于接口层与上层打包(所谓真DIP),还是与下层打包,有真正的价值和实用意义吗?

总之,DIP除了“倒置”和需要修改外,还是好的。在有OCP、针对接口编程,“抽象依赖原则”时,就显得多余。特别是在类设计层面,完全辞不达意。

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Sure, I'd be happy to answer your questions! 10.1. IoC stands for Inversion of Control, which is a design pattern used in software engineering. It is used to decouple the components of a system by allowing dependencies to be injected from outside the component rather than being created inside the component. This makes the system more flexible and easier to maintain. Here's an example of implementing IoC using pseudo-code: ``` class ComponentA { private ComponentB dependency; public ComponentA(ComponentB dependency) { this.dependency = dependency; } public void doSomething() { dependency.doSomethingElse(); } } class ComponentB { public void doSomethingElse() { // do something else } } // Usage: ComponentB dependency = new ComponentB(); ComponentA componentA = new ComponentA(dependency); componentA.doSomething(); ``` In this example, `ComponentA` has a dependency on `ComponentB`, but rather than creating an instance of `ComponentB` inside `ComponentA`, the dependency is passed in as a constructor parameter. This allows the dependency to be easily replaced with a different implementation if needed, without having to modify `ComponentA`. 10.4. DIP stands for Dependency Inversion Principle, which is another design principle used in software engineering. It states that high-level modules should not depend on low-level modules, but both should depend on abstractions. This allows for more flexibility and easier maintenance, as changes to low-level modules won't affect the high-level modules. If a designer depends too heavily on concretions (specific implementations), it can make the system difficult to change and maintain. For example, if a high-level module directly depends on a low-level module, it can be difficult to change the implementation of the low-level module without affecting the high-level module. This can lead to a lot of code changes and potential bugs. By depending on abstractions instead, the system becomes more flexible and easier to maintain.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值