最近,我读了一篇非常有趣的文章,探讨了典型的OO代码和功能更强的样式之间的区别。 即使在像Java和C#这样的OO语言中,对于功能的编码风格也有很多话要说。 我发现最大的缺点始终是代码组织之一:OO为您提供了一种组织大量代码的可发现方式。 虽然采用功能性样式,您可能需要较少的代码,但很难对其进行清晰组织。

我要挑战的并不是迈克的结论,而是他的出发点:他从他所描述的“典型的面向对象的C#代码”开始。 不幸的是,我认为他很厉害:即使在这个玩具示例中,也几乎就像我在野外看到的几乎所有所谓的“面向对象”代码一样。 我的类似代码的问题是:它不是面向对象的。 它是无规组织为类的过程代码。 只是因为你有上课,不要把它变成OO。

程序代码是什么意思? 我看到的典型模式是由两种类型的类组成的代码库:

  1. 值对象,无需业务逻辑即可保存所有数据
    如果它是您的持久层,nhibernate之类的对象,请在此额外加分。
  2. 具有一两个公共功能的类–它们作用于没有自身状态的价值对象
    这些几乎都是“名词”

名词性动词是OO代码差强人意的气味:OrderProcessor,AccountManager,PriceCalculator。 不,将其称为OrderService并不能使其更好。 它仍然是名词名词,您被毫无意义的“服务”一词所掩盖。 名词-动词表示其所有功能且没有状态,它作用于其他人的状态。 这几乎可以肯定是功能羡慕的标志。

这些名词动词的另一个设计气味是它们几乎总是单例。 哦,您可能没有意识到它们是单例的,因为您已经巧妙地将其隐藏在依赖注入框架的后面:但是它仍然是单例的。 如果没有状态,则可能是单例。 除了名称以外,这都是静态方法。 哦,确定它比实际使用“静态”一词更具可测试性。 但这仍然是静态方法。 如果您不使用自己的DI框架对自己撒谎,而将其编写为静态方法,则您会感到恐惧。 但是,因为您已将其打包,并称其为“依赖关系”,所以您认为可以。 好吧,不是。 它仍然是废话。 您所拥有的是过程,可以将它们随意分组为可笑的“依赖项”类。 可以肯定,这不是OO。

良好的OO设计的特性之一是,对数据进行操作的代码位于靠近数据的位置。 实际表示数据的方式可以隐藏在行为之后。 您关注的是对象的行为,而不是数据的表示。 这使您可以根据具有行为名词对域进行建模。 一个好的OO设计应包括与该领域中的名词相对应的类,其行为是对这些名词起作用的动词:Order.SubmitForPicking()。 UserAccount.UpdatePostalAddress(),Basket.CalculatePriceIn includedTaxes()。

这些是熟悉该领域而不是软件的人仍然会理解的词。 您的客户知道OrderPriceStrategyFactory的用途吗? 不,那不是真的。 它是你胡闹的胡扯。

具有讽刺意味的是,不受人喜爱的价值目标是真正解决设计问题的地方。 这些几乎都是领域中的实际名词。 他们只是缺乏任何使他们有用的行为。 回到Mike的例子:他有一个Customer类–它的公共接口只是一个电子邮件地址属性,一个经典的值对象:所有状态,没有任何行为[如果您想在家玩,我已经将Mike的代码复制到了git中回购 ; 以及我的重构版本 ]。

在这个领域,客户听起来像是一个好名词。 我敢打赌客户会知道客户是什么。 如果仅存在某些行为,则该域对象可能具有。 客户在Mike的世界中做什么? 好吧,此示例全部关于创建和发送报告。 报告是针对单个客户的,因此我认为我们可以要求客户创建自己的报告。 通过将方法从ReportBuilder移到“客户”,它就在其操作的数据旁边。 突然,公共电子邮件属性可能会被隐藏-这似乎是一个有用的更改,如果我们更改与客户联系的方式,那么只有客户需要更改,而不是ReportBuilder。 这几乎就像是将设计中的单个更改包含在单个类中。 也许有人应该就此单一责任的恶意代码写一个原则。

通过遵循这样的模式,将方法从名词-动词转移到它们所操作的名词上,我们最终得到了更清晰的设计。 客户可以创建Report(),报表可以RenderAsEmail(),电子邮件可以发送()。 在这样的领域中,这些似乎是明显的名词,并且这些名词具有明显的行为。 在软件的人造世界之外,它们都是有意义的。 该设计对领域建模,并且应该清楚域模型必须如何响应每个新要求而进行更改-因为每个都代表我们对领域的理解的变化。

那么,为什么这种模式如此罕见? 我指责IoC框架。 不严重,它们完全是邪恶的。 重构Mike的示例时,即使使用穷人的DI ,我遇到的第一件事就是我的域对象需要依赖项。 因为我现在已经移动了将报告从ReportingService通过电子邮件发送到Report域对象的功能,所以我的域对象现在需要了解Emailer。 在原始设计中,可以将其插入,但是对于新添加的对象,如何插入依赖项? 我需要在构造时或以电子邮件发送时将Emailer传递到我的报告中。 重构时,我选择在使用依赖项时将其传递,但​​这仅是因为在没有支持的情况下在构造时进行传递很麻烦。

几乎所有的DI框架都使这成为皇家的痛苦。 如果我要将依赖项注入到也具有状态的类中(例如客户报告的详细信息),则基本上是不可能的,因此没有人这样做。 只需将报表创建拉到ReportBuilder上,而让客户独自一人是更好,更简单,更快的方法。 但这是错误的。 客户值得拥有一些功能。 他有用。 他厌倦了只是作为价值的存储库。 如果只有一种方法可以将依赖项注入名词中,那绝对不是胡说八道。

例如,使用NInject(非常典型的DI框架),您可以创建一个域对象,该域对象需要通过字符串键入来注入依赖项和状态。 认真吗 在21世纪,您希望我放弃类型安全性,并将参数名称放入字符串中。 不,只是说不。

难怪当人们面对这些妥协时,人们就会选择名词-动词。 这些选择绝对可怕。 我见过的唯一可以使您正确执行此操作的DI框架是Guice的辅助注入。 据我所知,其他所有人都是错误的。

您的DI框架会杀死您的代码吗? 几乎可以肯定:如果您拥有有价值的对象和名词/名词,那么您的设计就是垃圾。 这是您的DI框架过分难以做出更好的设计的错。

翻译自: https://www.javacodegeeks.com/2015/09/your-di-framework-is-killing-your-code.html

您的DI框架正在杀死您的代码相关推荐

  1. 如何在ASP.NET Core应用中实现与第三方IoC/DI框架的整合?

    我们知道整个ASP.NET Core建立在以ServiceCollection/ServiceProvider为核心的DI框架上,它甚至提供了扩展点使我们可以与第三方DI框架进行整合.对此比较了解的读 ...

  2. 依赖注入[5]: 创建一个简易版的DI框架[下篇]

    为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在<依赖注入[4]: 创建一个简易版的DI框架[上篇]> ...

  3. 使用 DryIoc 替换 Abp 的 DI 框架

    一.背景 你说我 Castle Windsor 库用得好好的,为啥要大费周章的替换成 DryIoc 库呢?那就是性能,DryIoc 是一款优秀而且轻量级的 DI 框架,整个项目代码就两个文件,加起来代 ...

  4. 一个UI布局框架,以最少的代码实现UI设置及布局控制

    Petral-UI是一个以Swift实现的 UI布局框架,以最少的代码,实现UI的搭建.属性设置以及布局控制. 源码 Github地址:github.com/HuangZhiBin- 接入条件 swi ...

  5. 使用强大的 Mockito 测试框架来测试你的代码

    这篇教程介绍了如何使用 Mockito 框架来给软件写测试用例 1. 预备知识 如果需要往下学习,你需要先理解 Junit 框架中的单元测试. 如果你不熟悉 JUnit,请查看下面的教程: http: ...

  6. Python Web框架Tornado的异步处理代码演示样例

    1. What is Tornado Tornado是一个轻量级但高性能的Python web框架,与还有一个流行的Python web框架Django相比.tornado不提供操作数据库的ORM接口 ...

  7. mui框架mui-active高亮当前栏目 - 代码说明

    文章目录 mui框架mui-active高亮当前栏目 - 代码说明 项目案例 · 截图示下: 公共导航的代码: 1. `html`代码: 2. `js`代码: mui框架mui-active高亮当前栏 ...

  8. php框架 事件,php框架Minor5事件(附代码)

    5.1 事件Event Minor的 Event 类提供一个简单的观察者实现,允许您在应用程序里订阅与监听事件. 5.1.1 订阅事件 首先创建一个事件类: namespace App\Event;u ...

  9. Netty框架多人聊天案例,代码示例

    Netty框架多人聊天案例,代码示例 pom <?xml version="1.0" encoding="UTF-8"?> <project ...

最新文章

  1. Linux部署禅道环境
  2. 怎么用python实现回归_Python使用sklearn实现的各种回归算法示例
  3. canvas的getImageData和putImageDataAPI
  4. Content Provider的启动过程
  5. 自动排单功能的一些思考
  6. java encode_java的web开发中URLEncoder.encode方法
  7. 4键电子手表说明书_4键sport电子表使用说明书,按START键可循环选择12/24小时显示格式...
  8. P1192 台阶问题
  9. mysql实现添加图片_如何往mysql中添加图片
  10. Leet_Code_1
  11. h5的第一天 做的自定义调色器
  12. SQL代码建表时引用外键,有红线提示引用了无效的表
  13. DevOps 工程师成长日记系列四:打包
  14. java的虚引用_java虚引用的使用说明
  15. python关于 unittest的常见用法:前置条件与后置条件
  16. OpenGL的2个.Net版本
  17. 1. 随机事件 样本空间
  18. 学习人工智能需要参加哪些课程或培训,如何选择?
  19. android 蓝牙hf编程,基于Android蓝牙Inband ring功能实现.doc
  20. POE 供电设备原理详解

热门文章

  1. Windows10磁盘图标感叹号,Bitlocker提示等待激活
  2. PAT乙级(Basic Level)练习题 星际密码
  3. html自适应meta标签,seo常用meta标签:自适应网站设计对百度友好的关键
  4. 新学期,新FLAG——新征程
  5. web前端入门到实战:CSS鼠标悬浮图片模糊切换效果
  6. 用Matlab绘制相平面图
  7. CSS-justify-content 属性
  8. PAT(乙级)1090.危险品装箱(25)
  9. 物联网平台TZ-IOT发布透传云内测服务:V1.0
  10. 外企的那些所谓礼貌用语