编写干净代码的十大面向对象设计原则
披露:本篇文章包含附属链接;如果您通过本文提供的不同链接购买产品或服务,我可能会收到报酬。
面向对象设计原则是OOP编程的核心,但是我看到大多数Java程序员都在追求诸如单例模式、装饰器模式或观察者模式之类的设计模式,而没有对学习面向对象的分析和设计投入足够的重视。
学习面向对象编程的基础知识(例如抽象,封装,多态和继承)非常重要。但同时,了解面向对象的设计原则也同样重要。
它们将帮助您创建一个干净的模块化设计,以便于将来的测试、调试和维护。
我经常看到各种经验水平的 Java 程序员和开发人员,他们要么从未听说过这些OOP和SOLID 设计原则,要么根本不知道特定设计原则提供了什么好处以及如何在编码中应用这些设计原则。
为了尽自己的一份力,我把所有重要的面向对象设计原则都记录下来,并放在了这里,方便大家快速参考。这些原则至少能让你大致了解它们是什么,以及它们能带来哪些好处。
我没有放上例子,只是为了让文章简短,但你可以在互联网上,甚至在我的Java 博客上找到很多这些设计原则的例子,只需使用页面顶部的搜索栏即可。
如果您无法理解某个设计原则,您应该尝试做多个示例,因为有时我们会更好地连接到另一个示例或作者,但您必须理解这些设计原则并学习如何在您的代码中使用它。
你也可以参加一个综合性的面向对象设计课程,比如史蒂夫·史密斯在Pluralsight上讲授的《面向对象设计的SOLID原则》。这门课程对我理解和应用这些原则有很大帮助。
顺便说一句,我还分享了一些相关且实用的课程和书籍,有免费的也有付费的。如果你购买付费的课程和书籍,我也会赚一些钱。这些都是我学习 SOLID 设计原则和编程知识的资源,对于深入学习这些原则非常有用。
编写干净代码的 10 个 OOP 和 SOLID 设计原则
虽然学习任何设计原则或模式的最佳方式是现实世界的例子并了解违反该设计原则的后果,但本文的主题是向尚未接触或处于学习阶段的 Java 程序员介绍面向对象的设计原则。
我个人认为每个OOP和SOLID 设计原则都需要一篇文章来清楚地解释它们,我一定会尝试在这里做到这一点,但现在,只需准备好在设计原则镇快速骑行即可:)
1. DRY(不要重复自己)
我们的第一个面向对象设计原则是 DRY,顾名思义DRY(不要重复自己)意味着不要编写重复的代码,而是使用抽象将常见的东西抽象到一个地方。
如果您在两个以上的地方都有相同的代码块,请考虑将其作为单独的方法,或者,如果您多次使用硬编码值,请将其设置为public final const。这种面向对象设计原则的好处在于维护。
重要的是不要滥用它,重复不是为了代码,而是为了功能。
这意味着如果您使用通用代码来验证 OrderId 和 SSN,并不意味着它们是相同的或者它们将来会保持不变。
通过使用通用代码来实现两种不同的功能或事物,您可以将它们永远紧密地耦合在一起,并且当您的 OrderId 改变其格式时,您的 SSN 验证代码将会中断。
因此,要警惕这种耦合,不要将使用相似代码但不相关的代码组合在一起。您可以进一步学习“Java软件架构与设计模式基础”课程,以了解更多关于编写良好代码的方法以及设计系统时应遵循的最佳实践。
您还可以阅读 Dave Thomas 和 Andrew Hunt 合著的经典著作《程序员修炼之道》 ,其中首次提出了“DRY”这一术语,并解释了 DRY 的具体含义。
2. 封装变更内容
软件领域中只有一件事是不变的,那就是“变化”,因此,请封装您预计或怀疑将来会发生变化的代码。
这种 OOP 设计原则的好处是易于测试和维护适当封装的代码。
如果您使用 Java 编写代码,则遵循默认将变量和方法设为私有的原则,并逐步增加访问权限,例如从私有到受保护而不是公共。
Java 中的几种设计模式都使用了封装,工厂设计模式就是封装的一个例子,它封装了对象创建代码,并提供了以后引入新产品的灵活性,而不会对现有代码产生影响。
顺便说一句,如果你有兴趣了解更多关于 Java 和面向对象编程的设计模式,那么你一定要看看这门设计模式库课程 Pluralsight。它是最好的设计模式集合之一,并提供了如何在现实世界中使用它们的建议。
3.开放封闭设计原则
根据此 OOP 设计原则,“类、方法或函数应该对扩展(新功能)开放,对修改关闭”。
这是另一个美丽的 SOLID 设计原则,由 Bob 叔叔在他的经典著作《代码整洁之道》一书中提出,它可以防止某人更改已经过试验和测试的代码。
这一设计原则的主要好处是,已经试验过和测试过的代码不会受到影响,这意味着它们不会中断。
下面是一个违反编程开放封闭设计原则的 Java 代码示例:
在这段代码中,GraphicEditor 与 Shape 紧密耦合,如果需要一个新的 Shape,那么就需要修改drawShape(Shape s)
方法中已经尝试过和测试过的代码,这既容易出错,也不可取。
理想情况下,如果您只添加新功能,那么您的代码就应该经过测试,这就是开放封闭设计原则的目标。
顺便说一下,开放-封闭原则是 SOLID 首字母缩写中的“O”。如果你想了解更多关于这一原则的信息, Udemy 上的SOLID 面向对象设计和架构原则课程是最好的参考资源之一。
4.单一职责原则(SRP)
单一职责原则是 SOLID 的另一个设计原则,在 SOLID 的首字母缩写词中代表“S”。根据 SRP,一个类的变更原因不应超过一个,或者一个类应该始终只处理单一功能。
这一原则的主要好处是它减少了软件各个组件与代码之间的耦合。
例如,如果在 Java 中的一个类中放置多个功能,则会引入两个功能之间的耦合,即使更改一个功能,也有可能破坏耦合的功能,这需要进行另一轮测试以避免在生产环境中出现任何意外。
您可以进一步参阅Udemy 上 Dmitri Nestruk 的《Java 设计模式》课程,了解基于此原则的模式。
5.依赖倒置原则
无需请求依赖,框架会提供给您。Spring框架已经很好地实现了这一点,它是最流行的 Java 框架之一,可用于编写具有实际价值的应用程序。
这个设计原则的优点在于,任何由 DI 框架注入的类都很容易用模拟对象进行测试,而且更容易维护,因为对象创建代码集中在框架中,而客户端代码不会被这些代码所困扰。
有多种方法可以实现依赖注入,例如使用字节码检测(某些 AOP(面向方面编程)框架(如 AspectJ)所做的)或使用代理(就像在Spring中使用的)。
它也代表 SOLID 首字母缩略词中的“D”。
下面是违反 Java 中的依赖倒置原则 (DIP) 的代码示例:
您可以看到,AppManager
依赖于EventLogWriter
与紧密耦合的类AppManager
。如果您需要使用其他方式通知客户端,例如发送推送通知、短信或电子邮件,则需要更改AppManager
类。
这个问题可以通过使用依赖倒置原则来解决,其中框架不会AppManager
请求,而会将其注入或提供给 AppManager。EventLogWriter
您可以进一步参阅Udemy 上的《使用 SOLID 原则编写更好的代码 --- 速成课程》,以了解有关依赖倒置原则以及如何解决此类问题的更多信息。
6. 优先使用组合而不是继承
在 OOP 中,有两种常用方法可以重用您已经编写的代码,即继承和组合,它们都有各自的优点和缺点,但一般来说,如果可能的话,您应该始终选择组合而不是继承。
组合允许通过在运行时设置属性来改变类在运行时的行为,并通过使用接口来组成一个类,我们使用多态性来提供灵活性,可以随时用更好的实现来替换。
就连 Joshua Bloch 的《Effective Java》也建议优先使用组合而不是继承。如果您仍然不确定,也可以阅读此处,了解更多关于为什么组合在代码和功能复用方面优于继承的信息。
如果你总是忘记这条规则,这里有一幅漂亮的卡通画可以放在你的桌子上:-)
如果您有兴趣了解更多有关面向对象编程概念(如组合、继承、关联、聚合等)的知识,您还可以查看Coursera上的 Java 面向对象编程课程。
探索和学习是免费的,但如果您还想参加练习、作业、评估,并需要在您的 LinkedIn 个人资料中显示认证,则需要付费。
如果您参加本课程是为了获得 Coursera 证书,那么您需要注册专业课程或参加Coursera Plus等订阅计划,该计划提供对 5000 多个 Coursera 课程、项目和专业证书的无限制访问。
这不是一个设计原则,而是面向对象编程编码时的最佳实践。
7.里氏替换原则(LSP)
根据里氏替换原则,子类型必须可以替换超类型,我的意思是使用超类类型的方法或函数必须能够毫无问题地与子类的对象一起工作。
LSP与单一职责原则和接口隔离原则密切相关。
如果一个类具有更多功能,那么子类可能不支持某些功能,并且确实违反 LSP。
为了遵循LSP SOLID 设计原则,派生类或子类必须增强功能,而不是减少功能。LSP 代表 SOLID 首字母缩写中的“L”。
下面是一个违反 Java 中里氏替换原则的代码示例:
Java 中的里氏替换原则
违反 LSP 的原因是 Square 的行为与 Rectangle 的行为不匹配,例如,调用 setWidth 也会改变高度,而 Rectangle 则不会发生这种情况。
LSP 的另一个例子是 java.sql.Date,它违反了里氏替换原则,因为尽管 java.sql.Date 扩展了 java.util.Date,但您不能将它传递给需要 java.util.Date 的方法,因为所有与时间相关的方法(例如 getHour()、getMinute() 和 getSeconds() 方法)都会抛出 java.util.NotSupportedException。
如果您对更真实的例子感兴趣,那么Pluralsight 上的面向对象设计 SOLID 原则课程是一个不错的入门课程。
顺便说一句,你需要成为 Pluralsight 会员才能访问这门课程,费用约为每月 29 美元或每年 299 美元(14% 折扣)。即使你没有会员资格,也可以免费参加10 天的免费试用,无需任何承诺。这不仅可以免费访问这门课程,还可以在加入 Pluralsight 之前检查课程质量。
8.接口隔离原则(ISP)
接口隔离原则规定,如果客户端不使用某个接口,则它不应该实现该接口。
这种情况主要发生在一个接口包含多个功能,而客户端只需要一个功能而不需要其他功能时。
毫无疑问,接口设计是一项棘手的工作,因为一旦发布,就无法在不破坏所有实现的情况下对其进行修改。Java 8 的默认方法或防御方法功能确实提供了一种接口演进的方法,但并非所有编程语言都支持这些功能。
Java 中此设计原则的另一个好处是,接口的缺点是需要在任何类使用它之前实现所有方法,因此单一功能意味着需要实现的方法更少。
如果您没有在编码中获得接口的好处,那么我建议您阅读我的博客文章“Java 中接口的实际用途”以了解更多信息。
9. 为接口编程,而不是为实现编程
程序员应该始终针对接口而不是实现进行编程,这将导致灵活的代码可以与接口的任何新实现一起使用。
具体来说,您应该在Java中的变量、方法的返回类型或方法的参数类型上使用接口类型,就像使用SuperClass
类型来存储对象而不是使用一样SubClass
。
我是说
List numbers= getNumbers();
而不是
ArrayList numbers = getNumbers();
许多 Java 书籍也建议这样做,包括《Effective Java》和《Head First 设计模式》一书。
以下是 Java 中接口编码的示例:
如果您有兴趣提高程序的代码质量,我还建议您看看Udemy 上的重构设计模式课程,它将帮助您使用 C# 中的重构技术和设计模式改进内部设计。
10.授权原则
这是另一个有用的设计原则,它也遵循职责分离的逻辑。它说的是,不要自己做所有的事情,而要将其委托给相应的类。
委托设计原则的经典示例之一是Java 中的equals() 和 hashCode()方法。
为了比较两个对象是否相等,我们要求类本身进行比较,而不是由
Client
类进行检查。
这一设计原则的主要优点是无需重复代码,并且易于修改行为。事件委托是该原则的另一个例子,即将事件委托给处理程序进行处理。
概括
所有这些面向对象的设计原则都有助于您通过追求高内聚和低耦合来编写灵活、更好的代码。
理论是第一步,但最重要的是培养找出何时应用这些设计原则的能力。
掌握了这些之后,下一步就是学习 Java 中的设计模式,使用这些设计模式来解决应用程序开发和软件工程中的常见问题。
如果你正在寻找一门不错的入门课程,我建议你参加 Udemy 上的“从 0 到 1:设计模式——24 个重要的原则——Java课程”。这门课程内容非常全面,而且在他们几次限时抢购中,你只需 11 美元就能买到。
无论如何,这里对所有这些 OOP 设计原则进行了很好的总结。
找出我们是否违反了任何设计原则并损害了代码的灵活性,但同样,由于世界上没有什么是完美的,所以不要总是试图用设计模式和设计原则来解决问题,它们主要适用于维护周期较长的大型企业项目。
归根结底,专业程序员应该始终追求高内聚、低耦合的解决方案、代码或设计。浏览 Apache 和 Google 的开源代码是学习Java和面向对象编程 (OOP) 设计原则的好方法。
他们将向您展示如何在编码和 Java 程序中运用设计原则。Java 开发工具包遵循许多设计原则,例如类中的工厂模式BorderFactory
、类中的单例模式java.lang.Runtime
以及各种类中的装饰器模式java.io
。
如果您有兴趣学习面向对象的原则和模式,那么您可以看看我个人最喜欢的另一本书《Head First 面向对象分析与设计》,这是一本很棒的书,可能是面向对象分析和设计领域最好的材料
没有多少程序员知道这本书,因为它经常被更受欢迎的Eric Freeman所著的《Head First Design Pattern》所掩盖,后者更多地讲述了如何将这些原则结合在一起来创建一种可以直接用来解决已知问题的模式。
这些书籍对编写更优秀的代码大有裨益,充分利用了各种面向对象和 SOLID 设计原则。顺便说一句,如果你真的对 Java 编码实践更感兴趣,不妨阅读Joshua Bloch 的《Effective Java》第三版,这是 Java Collection API 编写者撰写的一本佳作。
如果您想了解有关 SOLID 设计原则的更多信息,可以查看以下一些有用的资源:
- 罗伯特·马丁 (Robert Martin) 撰写的《代码整洁之道》
- 面向对象设计的 SOLID 原则
- 面向对象设计和架构的 SOLID 原则
- Martin Fowler 的《重构》
如果你喜欢这篇文章,那么你可能也会喜欢这些关于 Java 和编程的文章:
Java 程序员应该学习的 10 件事、
每个程序员必读的 10 本书、
提高编程技能的 10 个技巧
、每个软件开发人员都应该知道的 10 种工具、
深入学习软件架构的 5 门课程
、Java 程序员应该知道的 20 个库和 API、
值得学习的 10 种编程语言、
Java 和 Web 开发人员应该学习的 10 个框架和库、
学习编码的 10 门最佳 Python 课程
感谢您阅读本文。如果您觉得这些面向对象设计原则有用,请与您的朋友和同事分享。如果您有任何问题或反馈,请留言。
顺便说一句,如果您使用本文中的链接购买我推荐的任何书籍或课程,我也会获得报酬。
如果您喜欢这篇文章,请考虑关注我(javinpaul)。如果您想收到每篇新文章的通知,请不要忘记在 Twitter 上关注javarevisited!
文章来源:https://dev.to/javinpaul/top-10-object-orient-design-principles-for-writing-clean-code-4pe1附言:如果你真的对编程充满热情,并且想要提升自己的编程技能,那么没有比Robert Martin的《代码整洁之道》和Martin P. Fowler的《重构》更好的书了。去读读吧。