面向对象编程中,有六大设计原则(也称 SOLID 原则),它们是软件设计的核心思想。遵循这些原则可以使代码更具扩展性、灵活性和可维护性。下面逐一介绍每个原则,并附带示例说明。
1. 单一职责原则(Single Responsibility Principle, SRP)
定义:一个类应该只有一个引起它变化的原因,即每个类都应该有一个单一的职责。
示例:假设有一个 User
类,用于处理用户的基本信息并负责将用户数据保存到数据库。此时 User
类包含了多种职责:用户信息管理和数据持久化。
违反单一职责的设计
class User {
private String name;
private String email;
public User(String name, String email) {
this.name = name;
this.email = email;
}
public void saveToDatabase() {
System.out.println("Saving user to database");
// 数据库保存逻辑
}
}
遵循单一职责原则的设计:将数据持久化的逻辑抽离到一个单独的 UserRepository
类中,让 User
仅负责用户数据管理。
class User {
private String name;
private String email;
public User(String name, String email) {
this.name = name;
this.email = email;
}
}
class UserRepository {
public void save(User user) {
System.out.println("Saving user to database");
// 数据库保存逻辑
}
}
2. 开闭原则(Open-Closed Principle, OCP)
定义:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭,即在不修改现有代码的情况下,扩展其行为。
示例:假设有一个 Shape
类,可以绘制不同形状的对象。如果以后要添加新的形状(如矩形、三角形),我们不应该修改原有代码。
不符合开闭原则的设计
class Shape {
public void draw(String shapeType) {
if (shapeType.equals("Circle")) {
System.out.println("Drawing a circle");
} else if (shapeType.equals("Square")) {
System.out.println("Drawing a square");
}
}
}
符合开闭原则的设计:使用多态,将不同形状的绘制行为放在各自的子类中。
interface Shape {
void draw();
}
class Circle implements Shape {
public void draw() {
System.out.println("Drawing a circle");
}
}
class Square implements Shape {
public void draw() {
System.out.println("Drawing a square");
}
}
3. 里氏替换原则(Liskov Substitution Principle, LSP)
定义:子类对象可以替换父类对象,且不会影响程序的正确性。
示例:假设有一个 Rectangle
类和一个 Square
类,Square
继承自 Rectangle
。若不遵循里氏替换原则,Square
的行为可能与 Rectangle
不一致,从而导致错误。
违反里氏替换原则的设计
class Rectangle {
protected int width, height;
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public int getArea() {
return width * height;
}
}
class Square extends Rectangle {
@Override
public void setWidth(int width) {
this.width = this.height = width;
}
@Override
public void setHeight(int height) {
this.width = this.height = height;
}
}
改进设计:将 Rectangle
和 Square
抽象为不同的类,不让 Square
继承 Rectangle
。
interface Shape {
int getArea();
}
class Rectangle implements Shape {
protected int width, height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
public int getArea() {
return width * height;
}
}
class Square implements Shape {
private int side;
public Square(int side) {
this.side = side;
}
public int getArea() {
return side * side;
}
}
4. 接口隔离原则(Interface Segregation Principle, ISP)
定义:不应强迫一个类实现它不需要的接口,即应将接口拆分为更小的、特定的接口。
示例:假设有一个 Worker
接口,其中包含了所有工作职责。如果 Worker
接口包含了 code
方法,所有实现了 Worker
的类都要实现该方法,这会导致不必要的实现。
违反接口隔离原则的设计
interface Worker {
void work();
void code();
}
class Manager implements Worker {
public void work() {
System.out.println("Managing work");
}
public void code() {
// 经理不需要实现编码工作
}
}
符合接口隔离原则的设计:将 Worker
接口拆分为多个小接口。
interface Work {
void work();
}
interface Coding {
void code();
}
class Manager implements Work {
public void work() {
System.out.println("Managing work");
}
}
class Programmer implements Work, Coding {
public void work() {
System.out.println("Programming work");
}
public void code() {
System.out.println("Writing code");
}
}
5. 依赖倒置原则(Dependency Inversion Principle, DIP)
定义:高层模块不应该依赖低层模块,两者都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。
示例:假设有一个 Notification
类,直接依赖于 Email
和 SMS
的具体实现,这种设计违反了依赖倒置原则。
不符合依赖倒置原则的设计
class Email {
public void send(String message) {
System.out.println("Sending email: " + message);
}
}
class Notification {
private Email email;
public Notification() {
email = new Email();
}
public void sendMessage(String message) {
email.send(message);
}
}
符合依赖倒置原则的设计:通过接口进行依赖注入,使 Notification
类依赖抽象而非具体实现。
interface MessageSender {
void send(String message);
}
class Email implements MessageSender {
public void send(String message) {
System.out.println("Sending email: " + message);
}
}
class Notification {
private MessageSender messageSender;
public Notification(MessageSender messageSender) {
this.messageSender = messageSender;
}
public void sendMessage(String message) {
messageSender.send(message);
}
}
6. 迪米特法则(Law of Demeter, LoD)
定义:一个对象应当对其他对象有最少的了解,即只与直接的朋友交流,避免调用链式方法或非直接关联的对象。
示例:假设有一个 Customer
类,它直接调用 Wallet
的 getBalance
方法,这是违反迪米特法则的。
违反迪米特法则的设计
class Wallet {
private double balance;
public Wallet(double balance) {
this.balance = balance;
}
public double getBalance() {
return balance;
}
}
class Customer {
private Wallet wallet;
public Customer(Wallet wallet) {
this.wallet = wallet;
}
public double getCustomerBalance() {
return wallet.getBalance(); // 直接访问 Wallet 的属性
}
}
符合迪米特法则的设计:在 Customer
中添加一个获取余额的方法,避免直接访问 Wallet
的细节。
class Wallet {
private double balance;
public Wallet(double balance) {
this.balance = balance;
}
public double retrieveBalance() {
return balance;
}
}
class Customer {
private Wallet wallet;
public Customer(Wallet wallet) {
this.wallet = wallet;
}
public double getBalance() {
return wallet.retrieveBalance(); // 间接访问 Wallet
}
}
总结
这六大设计原则在面向对象编程中相辅相成,有助于提高代码的结构化、模块化和可扩展性。