想要代码干净又整洁?这里有十大原则

这篇文章将介绍OOP和SOLID面向对象原则。

扫码关注《Java学研大本营》

面向对象的设计原则是OOP编程的核心,但我看到大多数Java程序员都在追逐Singleton模式、Decorator模式或Observer模式等设计模式,而没有把足够的注意力放在学习面向对象的分析和设计上。

学习抽象、封装、多态和继承等面向对象编程的基础知识很重要。但是,与此同时,了解面向对象的设计原则也同样重要。

它们将帮助你创建一个干净的、模块化的设计,这将便于测试、调试和将来的维护。

我经常看到不同经验水平的Java程序员和开发人员,要么从未听说过这些OOP和SOLID设计原则,要么根本不知道某个设计原则有什么好处,以及如何在编码中应用这些设计原则。

为了尽我所能,我已经记下了所有重要的面向对象的设计原则,并把它放在这里供大家快速参考。这些至少可以给你一些关于它们是什么以及它们提供什么好处的想法。

我没有举出例子,只是为了保持文章的简短,但你可以在互联网上,甚至在我的Java博客上找到很多这些设计原则的例子,只要使用页面顶部的搜索栏就可以了。

如果你不能理解一个设计原则,你应该尝试做多个例子,因为有时我们会与另一个例子或作者联系得更好,但你必须理解这些设计原则,并学习如何在你的代码中使用它。

你可以做的另一件事是加入一个全面的面向对象的设计课程,如Pluralsight上Steve Smith的SOLID面向对象设计原则。它对我理解和应用这些原则有很大帮助。

OOP和SOLID设计原则

虽然学习任何设计原则或模式的最好方法是现实世界的例子,并理解违反该设计原则的后果,但本文的主题是为Java程序员介绍面向对象的设计原则,他们要么没有接触过,要么正处于学习阶段。

我个人认为这些OOP和SOLID设计原则中的每一条都需要一篇文章来解释清楚,我一定会在这里尝试这样做,但现在,只要准备好在设计原则上快速浏览就可以了:)

1. DRY(不要重复自己)

我们的第一个面向对象的设计原则是DRY,顾名思义,DRY(不要重复自己)意味着不要写重复的代码,而是使用Abstraction来把常见的东西抽象在一个地方。

如果你有一个代码块出现在两个以上的地方,可以考虑把它变成一个单独的方法,或者如果你不止一次地使用一个硬编码的值,把它们变成公共的最终常量。这个面向对象的设计原则的好处在于维护

重要的是不要滥用它,重复不是为了代码,而是为了功能。

这意味着如果你用普通的代码来验证OrderId和SSN,并不意味着它们是一样的,或者它们在未来会保持不变。

通过对两个不同的功能或事物使用共同的代码,你将它们永远紧密联系在一起,当你的OrderId改变了它的格式,你的SSN验证代码将被破坏。

所以要小心这种耦合,不要把使用类似代码但不相关的东西结合起来。你可以进一步查看《Java中的软件架构和设计模式基础》课程,以了解更多关于写好代码和设计系统时应遵循的最佳实践。

你也可以阅读Dave Thomas和Andrew Hunt的经典书籍《务实的程序员》,该书首次提出了这个术语并解释了DRY的确切含义。

2. 封装变化的东西

在软件领域只有一件事是不变的,那就是 "变化",所以,封装你期望或怀疑在未来会被改变的代码。

这个OOP设计原则的好处是,它很容易测试和维护适当的封装代码。

如果你在用Java编码,那么请遵循这样的原则:默认情况下将变量和方法设为私有,并逐步增加访问权限,比如从私有到保护,而不是公开。

Java中的几个设计模式都使用了封装,工厂设计模式就是封装的一个例子,它封装了对象的创建代码,为以后引入新产品提供了灵活性,而且对现有代码没有影响。

Btw,如果你有兴趣学习更多关于Java和面向对象编程的设计模式,那么你必须查看这个设计模式库课程Pluralsight。它是设计模式的最佳集合之一,以及如何在现实世界中使用它们的建议。

3. 开放式封闭设计原则

根据这个OOP设计原则,"类、方法或函数应该是开放的,用于扩展(新功能),封闭的,用于修改"。

这是另一个美丽的SOLID设计原则,由Bob Uncle在他的经典的《Clean Code》一书中提出,它可以防止有人改变已经试过和测试过的代码。

这个设计原则的关键好处是,已经试过和测试过的代码不会被触及,这意味着它们不会被破坏。

这里有一个Java代码的例子,它违反了编程的开放封闭设计原则。

在这段代码中,GraphicEditor与Shape紧密相连,如果你需要一个新的Shape,那么你需要修改drawShape(Shape s)方法中已经被测试过的代码,这既容易出错,也不可取。

理想情况下,如果你只是添加新的功能,那么你的代码应该是经过测试的,这就是开放封闭设计原则的目标。

顺便说一下,开放-封闭原则的 "O "是来自SOLID的缩写。如果你想进一步了解这一原则,Udemy上的SOLID面向对象的设计和架构原则课程是最好的参考资源之一。

4. 单一责任原则(SRP)

单一责任原则是另一个SOLID设计原则,代表SOLID缩写中的 "S"。按照SRP,一个类不应该有一个以上的变化原因,或者一个类应该总是处理单一功能。

这个原则的关键好处是,它减少了软件和代码的单个组件之间的耦合。

例如,如果你在Java中把一个以上的功能放在一个类中,就会引入两个功能之间的耦合,即使你改变了一个功能,也有可能破坏了耦合的功能,这需要另一轮的测试,以避免在生产环境中出现任何意外。

你可以进一步参阅Dmitri Nestruk在Udemy上的《Javacourse中的设计模式》,以了解基于这一原则的模式。

5. 依赖性反转原则

不要要求依赖性,它将由框架提供给你。这一点在Spring框架中得到了很好的实现,Spring框架是最流行的用于编写真正有价值的应用程序的Java框架之一。

这个设计原则的好处是,任何被DI框架注入的类都很容易用模拟对象进行测试,而且更容易维护,因为对象的创建代码集中在框架中,而客户端的代码则不会有任何问题。

有多种方法可以实现依赖注入,比如使用一些AOP(面向方面的编程)框架(如AspectJ)的字节码工具,或者使用代理,就像Spring中使用的那样。

它也代表了SOLID缩写中的 "D"。

下面是一个违反Java中依赖反转原则或DIP的代码例子。

你可以看到AppManager依赖于EventLogWriter,而EventLogWriter与AppManager是紧密耦合的。如果你需要使用另一种方式来通知你的客户,如发送推送通知、短信或电子邮件,你需要改变AppManager类。

这个问题可以通过使用依赖反转原则来解决,AppManager不需要请求EventLogWriter,它将被注入或由框架提供给AppManager。

你可以进一步参阅Udemy上的Using SOLID Principles to Write Better Code --- A Crash Course来了解更多关于依赖反转原则以及如何解决此类问题。

6. 倾向于组合而不是继承

在OOP中,有两种方法可以重用你已经写好的代码,继承和组合,两者都有各自的优势和劣势,但是,一般来说,如果可能的话,你应该总是倾向于组合而不是继承。

有些人可能会争论这个问题,但我发现,组合比继承更灵活。

组合允许在运行时通过设置属性来改变一个类的行为,通过使用接口来组合一个类,我们可以使用多态性来提供灵活性,以便随时用更好的实现来替换。

甚至Joshua Bloch的《Effective Java》也建议使用组合而不是继承。如果你还不相信,那么你也可以阅读这里,以了解更多关于为什么你的组合比继承更能重用代码和功能。(http://javarevisited.blogspot.sg/2015/06/difference-between-inheritance-and-Composition-in-Java-OOP.html)

而且,如果你总是忘记这条规则,这里有一幅漂亮的卡通画,可以放在你的桌子上:-)

如果你有兴趣学习更多关于面向对象编程的概念,如组合、继承、关联、聚合等,你也可以看看Coursera上的Java面向对象编程课程。

这不是一个设计原则,而是比在面向对象编程中编码时的最佳做法。

7. 利斯科夫替代原则(LSP)

根据Liskov替代原则,子类必须可以替代超类,我的意思是使用超类类型的方法或函数必须能够毫无问题地与子类的对象一起工作"。

LSP与单一责任原则接口隔离原则密切相关。

如果一个类有更多的功能,那么子类可能不支持其中的一些功能,这样就违反了LSP。

为了遵循LSP的SOLID设计原则,派生类或子类必须增强功能,而不是减少功能。LSP代表SOLID缩写中的 "L"。

下面是一个违反了Java中Liskov替代原则的代码例子。

Java中的Liskov替代原则

违反LSP的原因是Square的行为与Rectangle的行为不一致,比如,调用setWidth也会改变高度,而Rectangle不是这样的。

还有一个LSP的例子是java.sql.Date,它违反了Liskov替换原则,因为即使java.sql.Date扩展了java.util.Date,你也不能把它传递给期望使用java.util.Date的方法,因为所有与时间有关的方法,例如getHour(), getMinute()和getSeconds()方法都会抛出java.util.NotSupportedException。

如果你对一个更真实的例子感兴趣,那么Pluralsight上的SOLID面向对象设计原则课程是一个不错的开始。

8. 接口隔离原则(ISP)

接口隔离原则指出,如果一个客户端不使用某个接口,就不应该实现该接口。

这种情况主要发生在一个接口包含一个以上的功能,而客户只需要一个功能而不需要其他功能的时候。

毫无疑问,接口设计是一项棘手的工作,因为一旦你发布了你的接口,你就不能在不破坏所有实现的情况下改变它。好吧,Java 8的默认或防御方法功能确实提供了一种接口进化的方式,但并不是所有的编程语言都支持这些功能。

这个设计原则在Java中的另一个好处是,接口的缺点是在任何类可以使用它之前实现所有的方法,所以拥有单一的功能意味着要实现更少的方法。

如果你不明白接口在编码中的好处,那么我建议你阅读我的博文,了解更多关于接口在Java中的真正用法。(http://www.java67.com/2014/02/what-is-actual-use-of-interface-in-java.html)

9. 为接口编程而不是为实现编程

程序员应该总是为接口编程,而不是为实现编程,这将导致灵活的代码,可以与接口的任何新实现一起工作。

具体来说,你应该在Java中的变量、方法的返回类型或方法的参数类型上使用接口类型,比如使用SuperClass类型来存储对象而不是使用SubClass

我的意思是

List numbers= getNumbers();

而不是

ArrayList numbers = getNumbers();

这在许多Java书籍中也有建议,包括Effective Java和Head First设计模式书籍。

下面是一个在Java中为接口编码的例子。

如果你对提高程序的代码质量感兴趣,我还建议你看看Udemy上的Refactoring to Design Patterns课程,它将帮助你用C#中的重构技术和设计模式改善内部设计。

10. 委托原则

这是另一个有用的设计原则,它也遵循职责分离的逻辑。它说,不要自己做所有的事情,把它委托给相应的类。

委托设计原则的一个经典例子是Java中的equals()和hashCode()方法。

为了比较两个对象是否相等,我们要求类本身进行比较,而不是由Client类进行检查。

这个设计原则的主要好处是没有重复的代码,而且相当容易修改行为。事件委托是这个原则的另一个例子,一个事件被委托给处理程序来处理。

总结

所有这些面向对象的设计原则都有助于你通过争取高内聚力和低耦合度来编写灵活和更好的代码。

理论是第一步,但最重要的是培养发现何时应用这些设计原则的能力。

一旦你掌握了这一点,下一步就是学习Java中的设计模式,用这些设计模式来解决应用开发和软件工程的常见问题。

总之,这里是所有这些OOP设计原则的一个很好的总结。

找出我们是否违反了任何设计原则,是否损害了代码的灵活性,但还是那句话,世界上没有完美的东西,不要总是试图用设计模式和设计原则来解决问题,它们主要用于大型企业项目,维护周期较长。

底线是,专业的程序员应该始终努力追求高度凝聚和松散耦合的解决方案、代码或设计。查看Apache和Google的开放源代码是学习Java和OOP设计原则的一些好方法。

他们会告诉你,在编码和Java程序中应该如何使用设计原则。Java开发工具包遵循许多设计原则,如BorderFactory类中的工厂模式,java.lang.Runtime类中的单子模式,各种java.io类中的装饰器模式。

如果你对学习面向对象的原则和模式感兴趣,那么你可以看看我的另一本个人最喜欢的《Head First Object-Oriented Analysis and Design》,这是一本非常好的书,可能是面向对象分析和设计方面最好的材料。

没有多少程序员知道这本书,因为它经常被它更受欢迎的表弟Eric Freeman的《Head First Design Pattern》所掩盖,后者更多的是关于这些原则如何结合在一起,创造一个你可以直接用来解决已知问题的模式。

这些书对写出更好的代码有很大帮助,充分利用了各种面向对象和SOLID设计原则。Btw,如果你真的对Java编码实践感兴趣,那么请阅读Joshua Bloch写的《Effective Java第三版》,这本书是写Java Collection API的人写的。

如果你想了解更多关于SOLID设计原则,这里有一些有用的资源你可以看一下。

Clean Code By [Robert Martin] 面向对象设计的SOLID原则 面向对象的设计和架构的SOLID原则 马丁-福勒的《重构》。

P. S. --- 如果你真的对你的编码有热情,并想提高你的编码技能,没有比罗伯特-马丁的《清洁代码》和马丁-P-福勒的《重构》更好的书了。去读一读吧。

推荐书单

《Java编程讲义》

购买链接:https://item.jd.com/13495830.html

《Java编程讲义》根据目前Java开发领域的实际需求,从初学者角度出发,详细讲解了Java技术的基础知识。

全书共15章,包括Java开发入门,Java语言基础,Java控制结构,数组,面向对象编程,继承和多态,抽象类、接口和内部类,异常处理,Java常用类库,集合与泛型,Lambda表达式,输入-输出流,多线程,JDBC数据库技术,网络编程等内容。内容全面覆盖.1ava开发必备的基础知识点,结合生活化案例展开讲解,程序代码给出了详细的注释,能够使初学者轻松领会Java技术精髓,快速掌握Java开发技能。

《Java编程讲义》适合作为高等院校相关专业的教材及教学参考书,也适合作为Java开发入门者的自学用书,还可供开发人员查阅、参考。

精彩回顾

深入理解Docker网络通信原理

详细&全面的RxJava架构原理与设计讲解

Java面试宝典大集锦

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值