用一个简单的例子来说明这六大设计原则(以单一职责原则、开闭原则、里氏替换原则、接口隔离原则、依赖倒置原则、迪米特法则为例)。
🧱 场景:图书管理系统
我们有一个系统,可以展示书籍信息和根据用户类型推荐书籍。现在我们要设计一个类结构,让它符合这些设计原则。
✅ 1. 单一职责原则(SRP)
问题:如果一个类既负责显示书籍信息,又负责推荐书籍,那它就有两个职责。
解决:
class BookDisplay {
void showBookDetails(Book book) {
// 显示书籍详情
}
}
class BookRecommender {
List<Book> recommendBooks(User user) {
// 根据用户推荐书籍
}
}
👉 每个类只做一件事,职责清晰。
✅ 2. 开闭原则(OCP)
问题:如果我们想增加一种新的推荐策略(比如按评分推荐),不应该去修改已有代码。
解决:
interface RecommendationStrategy {
List<Book> recommend(User user);
}
class PopularRecommendation implements RecommendationStrategy {
public List<Book> recommend(User user) {
// 推荐热门书籍
}
}
class RatedRecommendation implements RecommendationStrategy {
public List<Book> recommend(User user) {
// 推荐高评分书籍
}
}
👉 当新增策略时,只需扩展新类,不修改已有逻辑。
✅ 3. 里氏替换原则(LSP)
问题:子类不能破坏父类的行为。
解决:
abstract class BookService {
abstract void borrowBook(User user, Book book);
}
class RegularBookService extends BookService {
void borrowBook(User user, Book book) {
// 正常借书流程
}
}
class ReferenceBookService extends BookService {
void borrowBook(User user, Book book) {
throw new UnsupportedOperationException("参考书不可外借");
}
}
⚠️ 这样不符合 LSP,因为子类改变了父类行为。
✅ 正确做法是不要让 ReferenceBookService 继承 borrowBook() 方法,或者通过组合方式处理。
✅ 4. 接口隔离原则(ISP)
问题:如果一个接口定义了太多方法,客户端被迫实现不需要的方法。
解决:
interface Borrowable {
void borrow();
}
interface Readable {
void readOnline();
}
class EBook implements Borrowable, Readable {
public void borrow() { /* 可借阅 */ }
public void readOnline() { /* 支持在线阅读 */ }
}
class PaperBook implements Borrowable {
public void borrow() { /* 可借阅 */ }
}
👉 客户端只依赖自己需要的接口。
✅ 5. 依赖倒置原则(DIP)
问题:高层模块(如推荐器)不应直接依赖低层模块(如数据库操作)。
解决:
interface BookRepository {
List<Book> findAll();
}
class DatabaseBookRepository implements BookRepository {
public List<Book> findAll() {
// 从数据库获取数据
}
}
class BookRecommender {
private BookRepository repository;
BookRecommender(BookRepository repository) {
this.repository = repository;
}
List<Book> recommendBooks(User user) {
List<Book> books = repository.findAll();
// 推荐逻辑
}
}
👉 高层模块(BookRecommender)依赖于抽象(BookRepository),而不是具体实现。
✅ 6. 迪米特法则(LoD)
问题:对象之间耦合太紧,一个类知道太多其他类的内部细节。
解决:
class Library {
private BookCatalog catalog;
public List<Book> search(String keyword) {
return catalog.search(keyword); // 调用内部对象的方法,外部不知道catalog的存在
}
}
// 客户端使用:
List<Book> results = library.search("Java");
👉 外部类不知道 BookCatalog 的存在,只与 Library 打交道,降低了耦合。
✅ 总结一句话:
这些原则的核心思想是:解耦 + 可扩展 + 易维护。它们帮助我们写出更健壮、更灵活、更容易修改的代码。