前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >漫谈模式之几大设计原则

漫谈模式之几大设计原则

作者头像
孟君
发布2023-03-24 09:35:59
3610
发布2023-03-24 09:35:59
举报
文章被收录于专栏:孟君的编程札记

本文来简单介绍一下设计模式采用的几大原则。

单一职责原则

含义

单一职责原则(Single Responsibility Principle,SRP):一个类只负责一个功能领域中的相应职责或可以定义为:就一个类而言,应该只有一个引起它变化的原因。

举例

做一个简单的程序用做图表展示客户列表数据,其中包括图表的创建和展示、数据库连接和获取客户列表的方法,如下图所示:

图片
图片

从上图可以看出,CustomerDataChart其职责不够单一,其包括数据库连接、数据库操作、图表创建和展示,这些功能应该拆分到不同的类中,比如:

图片
图片

这样修改以后,数据库连接就由DBUtils来完成;CustomDao定义获取客户列表方法,其具体实现由DBUtil来完成;CustomerDataChart则包括图表的创建和展示,展示的内容则由CustomerDao来完成;经过上述调整,每个类都有单一的清晰的职责。

开闭原则

意图

开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代 码,而是要扩展原有代码,实现一个热插拔的效果。

先来看一个示例:

还是图表展示,其支持饼图和柱状图的展示:

图片
图片
图片
图片

如果我们需要增加一个其他图形的展示,我们需要增加else if的条件来进行扩展,这样原来的代码就别修改。

那么为了满足开闭原则,需要怎么做呢?那就要对系统采用抽象化设计抽象化是开闭原则的关键。

图片
图片

经过抽象化之后,ChartDisplay的变量就成为AbstarctChart,如果有新的Chart需要扩展,如增加一个AbcChart,那么AbcChart只要继承AbstractChart即可,如果ChartDisplay需要使用AbcChart进行图表展示,则其只要setChart(AbcChart)即可,这就满足了扩展,且不会对原有代码进行修改。

里氏替换原则

意图

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。里氏代换原 则中说,任何基类可以出现的地方,子类一定可以出现。

比如,我们有一个功能用于给普通用户和VIP用户发送邮件的功能,如下图所示:

图片
图片

我们可以看到,其实CommonCustomer和VipCustomer发送邮件很类似。我们可以采用里氏替换原则,可以采用如下具体步骤:

  • 建立抽象;通过抽象来建立规范;
  • 具体实现在运行时取代抽象;保证了系统的扩展性和灵活性;

修改后如下图所示,抽象一个Customer,EmailSender中send方法的参数为Customer即可。

图片
图片

这样,

代码语言:javascript
复制
Customer commomCus = new CommonCustomer();EmailSender.send(commomCus );就可以发送普通用户邮件;

同样,

代码语言:javascript
复制
Customer vipCus = new VipCustomer();EmailSender.send(vipCus );就可以发送VIP用户邮件;

依赖倒转原则

意图

面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。

比如,有一个小功能,读取文件中的用户名单,然后添加到数据库中。可以采用如下方式实现:

图片
图片

上述示例中,CustomDao与具体的文件数据转换类进行交互式,其不符合依赖倒转原则。依据依赖倒转原则,需要与具体类的上层接口或者抽象类交互,那么我们可以采用如下方式进行。

图片
图片

定义一个抽象类DataConvertor,其具有两个子类TXTDataConvertor和ExcelDataConvertor完成具体的数据转换。

至于CustomDao采用哪一种类型进行数据转换,其可以采用配置的方式进行。

这样,程序将不在于具体的实现类进行直接交互。关于依赖倒转原则,相信使用Spring来进行开发的同学深有体会。

接口隔离原则

意图

每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。

举个例子,自己实现ArrayList和LinkedList,我们可以定义一个List接口,

图片
图片

我们来实现LinkedList:

图片
图片

然后再来实现ArrayList:

图片
图片

想想这样做,有什么问题吗?

我们可以看到poll和peek方法,在ArrayList中用不到,但是我们却一定要实现它们,这就是因为List接口太大导致的。

我们可以创建一个新的接口:

图片
图片

然后移除之前List中的poll和peek方法:

图片
图片

这样,ListLinked的实现就变成:

图片
图片

ArrayList的实现为:

图片
图片

这思想不就是和JDK源代码中ArrayList和LinkList的思想一致吗~~

图片
图片
图片
图片

迪米特法则

意图

一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过 public 方法提供给外部。

代码语言:javascript
复制
一个软件实体应该尽可能少地和其它实体产生作用。

比如,我们很多人一起在线聊天,我说话不需要和每个人都说一下进行交互,只需要一个聊天室,就能将大家联系在一起。迪米特法则思想的体现,可以在中介者模式中体现,具体可以参考: 漫谈模式之中介者模式

七. 合成复用原则

意图

尽量使用合成复用,而不是采用继承来达到复用的目的。

比如,CustomerDao可以采用继承DBUtil完成数据库操作。

图片
图片

采用复用的方式,CustomerDao只要委托DBUtil来完成数据库操作,DBUtil其可以采用Oracle、MySQL或者其他数据库的链接实现,这样更加灵活。

图片
图片

再如:

代码语言:javascript
复制
当一个抽象可能有多个实现时,通常用继承来协调它们。抽象类定义对该抽象的接口,而具体的子类则有不同的方式加以实现。但是此方法有时候不够灵活。继承机制将抽象部分与它的实现部分固定在一起,使得难以对抽象部分和实现部分独立地进行修改、扩充和重用。

这个我在《漫谈设计模式之桥接模式》中已经做了详细的说明,有兴趣的同学可以去扩展看看。

小结

面向对象的一般原则,和其关系如下如图所示:

图片
图片

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 单一职责原则
  • 开闭原则
  • 里氏替换原则
  • 依赖倒转原则
  • 接口隔离原则
  • 迪米特法则
  • 七. 合成复用原则
  • 小结
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档