全国统一服务热线

177-0422-7313

新闻中心

当前位置:首页>新闻中心

软件设计原则

抽象的品质可以指导我们抽象与建模,但总归还是不够具象,在此基础上一些更落地更易执行的设计原则涌现出来,较的当属面向对象的设计原则 S.O.L.I.D。

1 开闭原则OCP

Software entities should be open for extension,but closed for modification

-- Bertrand Meyer 《Object Oriented Software Construction》

译:软件实体应当对扩展开放,对修改关闭。

开闭原则是Bertrand Meyer 1988年在 Object Oriented Software Construction 书中所提到一个观点,软件实体应该对扩展开放对修改关闭。我们来看一个关于开闭原则的例子,需要传进来的用户列表,分类型进行二次排序,我们代码可以这样写。

public List sort(List users, Enum type){ if(type == AGE){ // 按年龄排序 users = resortListByAge(users); }else if(type == NAME){ // 按名称首字母排序 users = resortListByName(users); }else if(type == NAME){ // 按客户健康分排序 users = resortListByHealth(users); } return users;}

上述代码就是一个明显违背开闭原则的例子,当我们需要新增一种类似时,需要修改主流程。由于这些方法都定义在私有函数中,我们哪怕对现有逻辑做调整,我们也需要修改到这份代码文件。

还有一种做法,可以实现对扩展开放对修改关闭,JDK的排序其实已经为我们定义了这样的标准。我们将不同的排序方式进行抽象,每种逻辑单独实现,单个调整逻辑不影响其他内容,新增排序方式也无需对已有模块进行调整。

2 依赖倒置DIP

High level modules shouldnot depend upon low level modules.Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions

--- Robert C.Martin C++ Report 1996

译:高层模块不应该依赖低层模块,两者都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。

Robert C.Martin是《Clean Code》《Code Architecture》两本经典书籍的作者,1996年他在C++ Report中发表了一篇名为 The Dependency Inversion Principle 的文章。他认为模块间的依赖应该是有序的,高层不应该依赖低层,低层应该依赖高层,抽象不应该依赖细节,细节应该依赖抽象。

怎么理解Robert C.Martin的这一观点。我们看这张图,我们的手可以握住这个杯子,是我们依赖杯子吗?有人说我们需要调杯子提供的hold服务,我们才能握住它,所以是我们依赖杯子。但我们再思考一下,棍子我们是不是也可以握,水壶我们也可以握,但猫狗却不行,为什么?因为我们的杯子是按照我们的手型进行设计的,我们定义了一个可握持的holdable接口,杯子依赖我们的需求进行设计。所以是杯子依赖我们,而非我们依赖杯子。

依赖倒置原则并非一个新创造的理论,我们生活的很多地方都有在运用。比如一家公司需要设立“法人”,如果这家公司出了问题,监管局就会找公司法人。并非监管局依赖公司提供的法人职位,它可以找到人,而是公司依赖监管局的要求,才设立法人职位。这也是依赖倒置的一种表现。

3 其他设计原则

这里没有一一将 S.O.L.I.D 一一列举完,大家想了解的可以自行查阅。除了SOLID之外,还有一些其他的设计原则,同样也非常。

PLOA较小惊讶原则

If a necessary feature has a high astonishment factor, it may be necessary to redesign the feature

-- Michael F. Cowlishaw

译:如果必要的特征具有较高的惊人因素,则可能需要重新设计该特征。

PLOA较小惊讶原则是斯坦福大家计算机教授 Michael F. Cowlishaw 提出的。不管你的代码有“多好”,如果大部分人都对此感到吃惊,或许我们应该重新设计它。JDK中就存在一例违反PLOA原则的案例,我们来看下面这段代码。

/** * Set a Formatter. This Formatter will be used * to format LogRecords for this Handler. *

* Some Handlers may not use Formatters, in * which case the Formatter will be remembered, but not used. *

* @param newFormatter the Formatter to use (may not be null) * @exception SecurityException if a security manager exists and if * the caller does not have LoggingPermission("control"). */public synchronized void setFormatter(Formatter newFormatter) throws SecurityException { checkPermission(); // Check for a null pointer: newFormatter.getClass(); formatter = newFormatter;}

在分享会上,我故意将这行注释遮盖起来,大家都猜不到 newFormatter.getClass() 这句代码写在这里的作用。如果要检查空指针,完全可以用Objects工具类提供的方法,实现完全一样,但代码表现出来的含义就千差万别了。

public static T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj;}

KISS简单原则

Keep it Simple and Stupid

-- Robert S. Kaplan

译:保持愚蠢,保持简单

KISS原则是 Robert S. Kaplan 提出的一个理论,Kaplan并非是一个软件学家,他是平衡积分卡Balanced Scorecard创始人,而他所提出的这个理论对软件行业依然适用。把事情变复杂很简单,把事情变简单很复杂。我们需要尽量让复杂的问题简明化、简单化。


QQ咨询
在线咨询
在线报名
177-0422-7313
177-0422-7313
返回顶部