今天我们来探讨一下“SOLID”原则在软件构造中的应用。
SOLID是面向对象程序设计中的五个基本设计原则,它们分别是SRP(单一职责原则)、OCP(开放封闭原则)、LSP(里式替换原则)、ISP(接口隔离原则)和DIP(依赖倒置原则)。这些原则可以帮助程序员设计出易于维护和扩展的软件系统,同时也提高了软件质量和减少了代码缺陷。
1 SRP(单一职责原则)
SRP是指一个类应该只有一个单一的责任,它在软件开发中的目的是将软件系统的不同部分分离出来,以便于更好地管理和维护。一个类的职责过多将会造成代码的复杂性和难度上升,同时也会导致代码的内聚性下降。因此,我们应该尽可能地将类的职责划分得越细越好,这样可以使得代码更加的清晰和易于理解。
示例如下,将Modem接口的功能分成两个接口实现。
interface Modem {
public void dial(String pno);
public void hangup();
public void send(char c);
public char recv();
}
interface DataChannel {
public void send(char c);
public char recv();
}
interface Connection {
public void dial(String phn);
public char hangup();
}
2 OCP(开放封闭原则)
OCP是指一个软件实体应该对扩展开放,对修改封闭。这个原则可以使得软件系统更加稳定和健壮,同时也可以降低修改代码时造成的影响。具体而言,我们应该采用抽象的方式定义接口和实现,将任务分离到不同的类中,从而使得系统更加灵活。
示例如下,有许多If else Switch 的代码维护起来十分麻烦,不能很好地满足OCP原则
public void drawShape(Shape s) {
if (s.m_type==1)
drawRectangle(s);
else if (s.m_type==2)
drawCircle(s);
}
public void drawCircle(Circle r)
{....}
public void drawRectangle(Rectangle r)
{....}
}
将功能拆分成一个个类,进行简化
class GraphicEditor {
public void drawShape(Shape s) {
s.draw();
}
}
class Shape {
abstract void draw();
}
class Rectangle extends Shape {
public void draw() {
// draw the rectangle
}
}
3 LSP(里式替换原则)
LSP是指一个能使用父类对象的地方,同样能使用子类对象。这个原则可以保证代码的兼容性和灵活性,同时也可以将继承的优点完全发挥出来。具体而言,我们应该将子类对象在其他地方的使用方法和父类保持一致,保证软件系统的可靠性和正确性。
4 ISP(接口隔离原则)
ISP是指不应该强迫一个类实现它不需要的接口,或者一个类应该有多个专用的接口,而不是一个大而全的接口。这个原则可以保证模块之间的解耦合,同时也可以减少代码的复杂性,提高代码的可读性和可维护性。
LSP原则的优秀代码示例:
interface Workable {
public void work();
}
interface Feedable{
public void eat();
}
interface Workable {
public void work();
}
interface Feedable{
public void eat();
}
ManWorker implements Workable, Feedable {
void work() {…};
void eat() {…};
}
RobotWorker implements Workable {
void work() {…};
}
5 DIP(依赖倒置原则)
DIP是指高层模块不应该依赖低层模块,二者应该依赖于抽象。我们应该采用接口的形式建立抽象并且实现它们,从而有效隔离不同层次的模块之间的依赖关系。这个原则可以提高代码的复用性和可扩展性,同时也可以保证软件的稳定性和灵活性。
优秀代码示例:
public class EmployeeService {
private EmployeeFinder emFinder; //concrete class, not abstract.
//Can access a SQL DB for instance
public Employee findEmployee(…) {
emFinder.findEmployee(…)
}
}
//DIP - fixed
public class EmployeeService {
private IEmployeeFinder emFinder
//depends on an abstraction, no an implementation
public Employee findEmployee(…) {
emFinder.findEmployee(…)
}
}