《敏捷软件开发》— 设计原则(一)
一、单一职责原则(SRP)
就一个类而言,应该仅有一个引起它变化的原因。
这项设计原则体现了模块的内聚性要求。当需求变化时,该变化会反映为类的功能的变化。如果一个类承担了多于一个的职责,那么就可能有多个原因导致其发生变化。一个职责的变化可能会抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,无法很好的响应变化。
1、职责
在 SRP 中,我们把职责定义为变化的原因。如果能想到多于一个的动机去改变一个类,那么这个类就是具有多于一个的职责。有时,我们很难注意到这一点。我们习惯于以组的形式去考虑职责。例如,考虑下面 Modem 接口:
interface Modem {
public void dial(String pno);
public void hangup();
public void send(char c);
public void recv();
}
初始看来,这个接口很合理。然而, 它实际承担了两个职责:连接和通信。那么这两个职责应该被分开吗?这依赖于需求的变化。如果二者的变化总是独立的,例如经常需要在保持通信方式的情况下,修改连接接口,那么这两种职责就应该被分离;另一方面,如果它们总是成对地发生变化,那么就不需要分离它们。
2、分离耦合的职责
二、开放-封闭原则(OCP)
软件实体(类、模块、函数等)应该是可以扩展的,但是不可修改的
如果程序中的一处改动会产生连锁反应,导致一系列相关模块的改动,那么设计就具有僵化性的臭味。OCP 建议我们应该对系统进行重构,这样以后对系统再进行那样的改动时,就不会导致更多的修改。如果正确使用 OCP, 那么以后再进行同样的改动时,就只需要添加新的代码,而不必改动已经正常运行的代码。
1、抽象
实现 OCP 的基础在于抽象。如果模块 A 依赖于模块 B,而模块 B 的实现又经常发生变化,那么我们可以让 A 仅依赖于 B 的抽象接口类:
这样,当我们新增服务器类型时,不需要修改 Client 类(显然,配置类关系的地方需要修改)。
2、Shape 程序
一个很常见的违反OCP的例子如下:
// Shape.h
enum ShapeType {
e_Circle,
e_Square
};
struct Shape
{
ShapeType shapeType;
};
// Circle.h
struct Circle : public Shape
{
double radius;
Point center;
};
// Square.h
struct Square : public Shape
{
double side;
Point topLeft;
};
// drawAllShapes.cpp
void drawAllShapes(Shape* shapes[