五大基本原则
面向对象编程(OOP)有五个基本原则,通常被称为 SOLID 原则。它们分别是:
- 单一职责原则(Single Responsibility Principle,SRP)一个类应该只负责一个功能领域中的相应职责。
- 开放封闭原则(Open/Closed Principle,OCP)类应该对修改关闭,对扩展开放。
- 里氏替换原则(Liskov Substitution Principle,LSP)子类必须能够替换掉它们的基类。
- 接口隔离原则(Interface Segregation Principle,ISP)不应该强迫客户端依赖于它们不需要的接口。
- 依赖反转原则(Dependency Inversion Principle,DIP)高层模块不应该依赖于低层模块,它们都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
单一职责原则(SRP)
一个类应该只有一个引起变化的原因。换句话说,一个类应该只负责一个功能。如果一个类承担了过多的责任,就会导致类的功能不清晰、难以维护和扩展。
class FileHandler {
public function readFile($filename) {
// 读取文件的代码
}
public function processData($data) {
// 处理数据的代码
}
}
# FileHandler 类承担了读取文件和处理数据两个职责,违反了单一职责原则。更好的做法是将这两个功能拆分到不同的类中。
开放封闭原则(OCP)
软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。这意味着当需要改变程序的行为时,应该通过扩展现有的代码,而不是修改已有的代码。
interface Shape {
public function draw();
}
class Circle implements Shape {
public function draw() {
return "Drawing a circle.";
}
}
class Rectangle implements Shape {
public function draw() {
return "Drawing a rectangle.";
}
}
# 在这个示例中,如果需要增加一个新的形状,只需要创建一个新的类并实现 Shape 接口,而不需要修改 Circle 和 Rectangle 类。
里氏替换原则(LSP)
子类型必须能够替换掉它们的父类型。这意味着在使用继承时,子类必须能够替代父类而不影响程序的正确性。
class Bird {
public function fly() {
// 鸟飞行的代码
}
}
class Duck extends Bird {
public function fly() {
// 鸭子飞行的代码
}
}
# 在这个示例中,Duck 类继承自 Bird 类,但是鸭子不会像鸟一样飞得很高,这违反了里氏替换原则。更好的做法是将鸟的飞行行为抽象为接口或抽象类,并在需要的子类中实现。
接口隔离原则(ISP)
客户端不应该被迫依赖它们不使用的接口。接口应该足够小,以确保客户端只需知道它们感兴趣的方法。
interface Animal {
public function eat();
public function sleep();
}
class Dog implements Animal {
public function eat() {
// 狗吃的代码
}
public function sleep() {
// 狗睡觉的代码
}
}
class Bird implements Animal {
public function eat() {
// 鸟吃的代码
}
public function sleep() {
// 鸟睡觉的代码
}
public function fly() {
// 鸟飞行的代码
}
}
# 在这个示例中,Bird 类实现了 Animal 接口,但是鸟不会像动物一样睡觉,这违反了接口隔离原则。更好的做法是将 Animal 接口拆分为更小的接口,以确保实现类只需实现自己需要的方法。
依赖反转原则(DIP)
高级模块不应该依赖于低级模块,两者都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。
interface Logger {
public function log($message);
}
class FileLogger implements Logger {
public function log($message) {
// 记录日志到文件的代码
}
}
class DatabaseLogger implements Logger {
public function log($message) {
// 记录日志到数据库的代码
}
}
# 在这个示例中,高级模块(如业务逻辑类)不依赖于具体的日志记录方式(低级模块),而是依赖于抽象的 Logger 接口。这样,在需要更改日志记录方式时,只需更改依赖注入的具体实现,而不需要修改高级模块的代码。
文章评论