正交性的好处和实现方法

http://tommwq.tech/blog/2020/11/19/223

1 软件开发中的正交性

在几何学中,“正交”一词可以简单的理解为“垂直”。软件工程借用了这个术语,用来表示两个软件模块的耦合程度低。正交性高的软件更加灵活、更易于扩展和修改,拥有更长的生命周期、和更低的维护成本。

如果两个对象相互感知(关联、依赖)到对方,二者之间就发生了耦合。正交性就是低耦合性。当一个模块发生变更,与其耦合的模块也需要进行调整,以适配变更。正交性低的软件,需要适配的模块越多。即使一个很小的需求变化,也可能引发大量的代码修改。对于软件来说,修改意味着成本和(引入缺陷的)风险。如果放任成本和风险持续上涨,软件项目很快会变得无法推进,即无法应对需求变化,也无法修补缺陷。因此为了维持软件的竞争力,需要提高正交性。

2 单一职责原则

提高正交性的根本方式就是时刻遵循单一职责原则。

There should never be more than one reason for a class to change.

Single Responsibility Principle

我们从一个例子来理解单一职责原则。

Listing 1: 违反单一职责原则

public class Printer {
    public void print(String message) { /* ... */ }
    public void print(String fmt, Object object) {
        print(format(fmt, object));
    }
    public String format(String fmt, Object object) { /* ... */ }
}

如果软件需要支持一种新的打印格式,Printer.format方法就要发生改变。如果软件需要支持一种新的打印设备,Printer.print方法也要发生改变。有两个原因会引发Printer类的改变,这是因为Printer类承担了打印和格式化两个职责。如果采用单一职责原则,应当将打印和格式化职责分离。

Listing 2: 遵守单一职责原则

public class Formatter {
    public String format(String fmt, Object object) { /* ... */ }
}

public class Printer {
    public void print(String message) { /* ... */ }
    public void print(String fmt, Object object) {
        Formatter formatter = new Formatter();
        print(formatter.format(fmt, object));
    }
}

3 应用单一职责原则

3.1 分离接口定义和接口实现职责(面向接口编程)

这是单一职责原则最简单也是最常见的应用。

3.2 分离(类层面的)读写职责

这里提到的,不是持久层(数据库)的读写分离,而是在类层面,将读操作和写操作分离。这么做的好处有语义更清晰、读接口是幂等的、以及可以避免不必要的写操作。

Listing 3: 未分离读写接口

public class Calculator {
    public int add(int value) { ... }
}

Listing 4: 分离读写接口

public class Calculator {
    public int add(int value) { ... }
    public int getResult() { ... }
}   

3.3 分离类的创建和使用(依赖注入)

Listing 5: 未分离创建和使用

public class Printer {
    public void print(String message) { /* ... */ }
    public void print(String fmt, Object object) {
        Formatter formatter = new Formatter();
        print(formatter.format(fmt, object));
    }
}   

Listing 6: 分离创建和使用

public class Printer {
    public Printer(Formatter formatter) {
        this.formatter = formatter;
    }
    public void print(String message) { /* ... */ }
    public void print(String fmt, Object object) {
        print(formatter.format(fmt, object));
    }
}

3.4 分离业务模型、控制模型和试图模型(MVC、MVVM、MVP)

参考 

MVC、MVP和MVVM - tommwq.tech/blog

4 如何度量正交性

目前没有很好的度量正交性的方法。考虑到正交性意味着低耦合度,而耦合度是软件模块之间的感知程度,我们可以用下面的公式来描述正交性:

orthogonality = n*(n-1)/k

其中n是软件中模块的数量,k是模块之间依赖关系的数量。如果k=0,我们将正交性定义为正无穷大。

假设软件包含n个模块,这些模块按照依赖关系构成了一个有向图。当每个模块都依赖于其他模块时,依赖关系数量最多,是n*(n-1)个。当各模块互不依赖时,依赖关系数量是0。我们用k表示模块依赖关系数量,显然k衡量了模块之间的耦合度。k的值域依赖于模块数n,我们对k做归一化处理,让k除以n*(n-1),就得到了值域是[0,1]的耦合度度量函数。考虑到正交性和耦合度呈类似反比例的关系,再取倒数就得到了上面的公式。

你可能感兴趣的:(经验分享)