接口
接口有很多不同的概念,在这里,这个术语指的是类里的接口。类实现了许多方法,有些方法旨在被其他对象使用,这些方法就组成了它的公共接口。那些组成类的公共接口的方法组成了这个类呈现给外部世界的全貌。他们: 1. 暴露了其主要的职责 2. 期望被其它对象调用 3. 不会因一时兴起而改变 4. 对其他依赖它的对象来说很安全 5. 在测试里被详细记录
领域对象
Domain Object 显而易见,因为他们代表了这个应用程序,代表了现实世界里的很大的、易于发现的事物。应该要注意的是,Domain Object 往往是给粗心大意设立的陷进。因为如果过度关注他们,就会倾向于给他们强加上行为。我们应该重点关注的是他们之间的消息传递,这些消息会引导你去发现其他的对象,而这些对象可远没有这么明显。
时序图
时序图的价值在于,他们明确制定了对象之间消息的传递。因为对象间只应使用公共接口进行通信,时序图便是一种用于暴露、实验并最终定义这些接口的工具。
请询问“要什么”,别告知“如何做”
如下图, Trip
告知 Mechanic
如何去准备每一辆 bicycle.
下图里,Trip
要求 Mechanic
去准备每一个 bicycle
消息的这种变化是代码可维护性的一个巨大改进。因为它大大缩短了公共接口,大大减少出现“违背其承诺,然后强迫许多类进行更改”的情况。
最小化上下文(context)
对象所了解到的关于其他对象的那些事情便构成了它的上下文。对象所期待的上下文会直接影响到它的重用难度。具有简单上下文的对象易于使用,也易于测试,他们对周边的环境期望很少。最好的情况是对象与他的上下文完全独立。如果某个对象在与其他对象进行合作时,不知道他们是谁,也不知道他们所做的事情,那么这个对象便可以按各种千奇百怪和完全无法预测的方式重用。
信任其他对象
我知道我需要什么,并且我相信你会做好你的本职工作。
这种盲目的信任是面向对象设计的基石。在允许对象进行合作的同时,它无需将自己束缚在上下文里,并且在任何期望壮大和变化的应用程序里它都是必不可少的。
创建显式接口
- 被明确标识;
- 多与
做什么
有关,少于怎么做
有关; - 尽可能让这些名字都稳定不变;
- 将散列表作为参数
迪米特法则
迪米特法则会限制可以向某个方法发送消息的对象集合。它会禁止这样的做法:将某条消息通过第二个不同类型的对象转发给第三个对象。
1 | # 不合理 |
1 | # 合理 |
鸭子类型
Ducking Type
指的是不会绑定到任何特定类的公共接口。这种跨类的接口能为应用程序带来巨大的灵活性,所采用的方式是利用更加宽容的消息依赖取代昂贵的类依赖。
1 | ## 不好的写法 |
删除依赖关系的关键是要意识到:Trip
和Prepare
方法只服务于单个目的,因此它的参数出现在这里是希望可以协作完成同一个目标。每一个参数都因同样的理由出现在这里,具体的原因与这些参数的底层类无关。 设计鸭子类型的挑战是:要注意到你需要一个鸭子类型,并且要将其接口抽象出来
1 | ## 好的写法 |