面向对象编程中,有六大设计原则(也称 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 {@Overridepublic void setWidth(int width) {this.width = this.height = width;}@Overridepublic 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}
}
总结
这六大设计原则在面向对象编程中相辅相成,有助于提高代码的结构化、模块化和可扩展性。