学会这10个设计原则,离架构师又进了一步!!!

 

闲言碎语:

 

一个懂设计原则的程序猿,写出来的代码可扩展性就是强,后续的人看代码如沐春风。相反,如果代码写的跟流水账似的,完全一根筋平铺下来,后续无论换谁接手维护都要骂娘。

 

做软件开发多年,仿佛已经形成一种惯性,深入骨髓,按照常规的结构拆分:、、,一个功能只需要个把小时代码就撸完了。

再结合和 绝世秘籍,一个个功能点便如同雨后春笋般被快速克隆实现。

是不是有种雄霸天下的感觉,管他什么业务场景,大爷我一梭到底,天下无敌!!!

 

可现实真的是这样/strong>

答案不言而喻!!!

初入软件行业,很多人都会经历这个阶段。时间久了,很多人便产生困惑,能力并没有随着工作年限得到同比提升,焦虑失眠,如何改变现状/p>

悟性高的人,很快能从一堆乱麻中找到线索,并不断的提升自己的能力。

什么能力/strong>

当然是软件架构能力,一名优秀的软件架构师,要具备复杂的业务系统的、、、。

如何培养这样能力/strong>

 

我将常用的软件架构原则,做了汇总,目录如下:

 

 

当然这些原则有些是相互辅助,有些是相互矛盾的。实际项目开发中,要根据具体业务场景,灵活应对。

 

 

单一职责

 

我们在编码的时候,为了省事,总是喜欢在一个类中添加各种各样的功能。未来业务迭代时,再不断的修改这个类,导致后续的维护成本很高,耦合性大。牵一发而动全身。

为了解决这个问题,我们在架构设计时通常会考虑

定义:

单一职责(SRP:Single Responsibility Principle),面向对象五个基本原则(SOLID)之一。每个功能只有一个职责,这样发生变化的原因也会只有一个。通过,尽量减少错误的发生。

单一职责原则和一个类只干一件事之间,最大的差别就是,将变化纳入了考量。

代码要求:

一个接口、类、方法只负责一项职责,简单清晰。

优点:

降低了类的复杂度,提高类的可读性、可维护性。进而提升系统的可维护性,。

示例:

有一个用户服务接口,提供了用户注册、登录、查询个人信息的方法,主要还是围绕用户相关的服务,看似合理。

过了几天,业务方提了一个需求,用户可以参加项目。简单的做法是在类中增加一个方法

又过了几天,业务方又提了一个需求,统计一个用户参加过多少个项目,我们是不是又在类中增加一个方法。

这样导致的后果是,类的职责越来越重,类会不断膨胀,内部的实现会越来越复杂。既要负责用户相关还有负责项目相关,后续任何一块业务变动,都会导致这个类的修改。

两类不同的需求,都改到同一个类。正确做法是,把不同的需求引起的变动拆分开,单独构建一个类,专门负责项目相关的功能

这样带来的好处是,用户相关的需求只要改动。如果是项目管理的需求,只需要改动。二者各自变动的理由就少了很多。

 

开闭原则

 

开闭原则(OCP:Open-Closed Principle),主要指一个类、方法、模块 等 对扩展开放,对修改关闭。简单来讲,一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。

个人感觉,开闭原则在所有的原则中最重要,像我们耳熟能详的23种设计模式,大部分都是遵循开闭原则,来解决代码的扩展性问题。

 

实现思路:

采用抽象构建框架主体,用实现扩展细节。不同的业务采用不用的子类,尽量避免修改已有代码。

优点:

  • 可复用性好。在软件完成以后,仍然可以对软件进行扩展,加入新的功能,非常灵活。因此,这个软件系统就可以通过不断地增加新的组件,来满足不断变化的需求。

  • 可维护性好。它的底层抽象相对固定,不用担心软件系统中原有组件的稳定性,这就使变化中的软件系统有一定的稳定性和延续性。

示例:

比如有这样一个业务场景,我们的电商支付平台,需要接入一些支付渠道,项目刚启动时由于时间紧张,我们只接入,那么我们的代码这样写:

随着业务扩展,后期开始逐步接入一些其他的支付渠道,比如、、、、等,要如何迭代/p>

所有的业务逻辑都集中到一个方法中,每一个支付渠道本身的业务逻辑又相当复杂,随着更多支付渠道的接入,方法中的代码逻辑会越来越重,维护性只会越来越差。每一次改动都要回归测试所有的支付渠道,劳民伤财。那么有没有什么好的设计原则,来解决这个问题。我们可以尝试按开闭原则重新编排代码

首先定义一个支付渠道的抽象接口类,把所有的支付渠道的骨架抽象出来。设计一系列的插入点,并对若干插入点流程关联。

关于插入点,用过OpenResty的同学都知道,通过set_by_lua、rewrite_by_lua、body_filter_by_lua 等不同阶段来处理请求在对应阶段的逻辑,有效的避免各种衍生问题。

逐个实现不同支付渠道的子类,如:、,每个渠道都是独立的,后期如果做渠道升级维护,只需修改对应的子类即可,降低修改代码的影响面。

总调度入口,遍历所有的支付渠道,根据里的参数,判断当前渠道是否处理本次请求。

当然,也有可能采用的方式,比如,+,可以通过上下文参数,传递一些中间态的数据。

 

里氏替换

 

里氏替换原则(LSP:Liskov Substitution Principle):所有引用基类的地方必须能透明地使用其子类的对象

简单来讲,子类可以扩展父类的功能,但不能改变父类原有的功能(如:不能改变父类的入参,返回),跟面向对象编程的类似。

多态是面向对象编程语言的一种语法,是一种代码实现的思路。而里氏替换是一种设计原则,是用来指导继承关系中子类如何设计,子类的设计要保证在替换父类的时候,不改变原有程序的逻辑以及不破坏原有程序的正确性。

实现思路:

  • 子类可以实现父类的抽象方法

  • 子类中可以增加自己特有的方法。

  • 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。

  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

 

接口隔离

 

接口隔离原则(ISP:Interface Segregation Principle)要求程序员尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含调用方感兴趣的方法,而不应该强迫调用方依赖它不需要的接口。

实现思路:

  • 接口尽量小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。

  • 为依赖接口的类定制服务。只提供调用者需要的方法,屏蔽不需要的方法。

  • 结合业务,因地制宜。每个项目或产品都有特定的环境因素,环境不同,接口拆分的标准就不同,需要我们有较强的业务 sense

  • 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。

示例:

用户中心封装了一套接口,给上层调用(业务端以及管理后台)提供用户基础服务。

但随着业务衍化,我们需要提供一个删除用户功能,常规的做法是直接在接口中增加一个方法,比较简单。

但这样会带来一个安全隐患,如果该方法被普通权限的业务方误调用,容易导致误删用户,引发灾难。

如何避免这个问题,我们可以采用的原则

定义一个全新的接口服务,并提供方法,接口只提供给Bops管理后台系统使用。

总结一下,在设计微服务接口时,如果其中一些方法只限于部分调用者使用,我们可以将其拆分出来,独立封装,而不是强迫所有的调用方都能看到它。

 

依赖倒置

 

软件设计中的细节具有多变性,但是抽象相对稳定,为了利用好这个特性,我们引入了依赖倒置原则。

依赖倒置原则(DIP:Dependence Inversion Principle):高层模块不应直接依赖低层模块,二者应依赖于抽象;抽象不应该依赖实现细节;而实现细节应该依赖于抽象。

依赖倒置原则的主要思想是要面向接口编程,不要面向具体实现编程。

示例:

定义一个消息发送接口,具体的实例Bean注入到,触发完成消息的发送。

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年5月10日
下一篇 2021年5月10日

相关推荐