设计模式六大原则
设计模式六大原则,也称为SOLID原则,是面向对象设计中用于提高代码可读性、可维护性和可扩展性的重要指导原则。这些原则分别是:
-
单一职责原则(Single Responsibility Principle, SRP):一个类应该仅有一个引起它变化的原因。这意味着一个类应该只负责一项职责,从而避免类的功能过于复杂,提高类的内聚性。
-
开放封闭原则(Open-Closed Principle, OCP):软件实体(类、模块、函数等)应该可以扩展,但是不可修改。这意味着软件实体应该在不修改现有代码的情况下进行扩展,以适应新的需求变化。
-
里氏替换原则(Liskov Substitution Principle, LSP):所有引用基类的地方必须能透明地使用其子类的对象。这意味着子类不应该破坏父类的行为,即子类继承父类后,可以扩展父类的功能,但不能改变父类原有的功能。
-
依赖倒置原则(Dependency Inversion Principle, DIP):高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。这意味着应该通过接口或抽象类来定义模块间的依赖关系,而不是直接依赖具体的实现类。
-
接口隔离原则(Interface Segregation Principle, ISP):客户端不应该依赖它不需要的接口。这意味着一个类对另一个类的依赖应该建立在最小的接口上,不要强迫客户端依赖于它们不用的方法。
-
迪米特法则(Law of Demeter, LOD)或最少知识原则:一个对象应该对其他对象保持最少的了解。这意味着一个类应该对自己需要耦合或调用的类知道得最少,从而减少类之间的依赖关系,提高模块的独立性。
遵循这些原则可以帮助开发人员设计出更加健壮、易于维护和扩展的软件系统。当然,我可以通过具体的示例来讲解设计模式六大原则。以下是每个原则的示例讲解:
1. 单一职责原则(Single Responsibility Principle, SRP)
示例:考虑一个用户管理类(UserManager
),如果它同时负责用户信息的存储、验证、权限检查等多个职责,那么当任何一个职责发生变化时,都可能需要修改这个类。根据单一职责原则,我们可以将这个类拆分为多个类,如UserRepository
(负责用户信息的存储)、UserValidator
(负责用户信息的验证)、AuthorizationService
(负责权限检查)等。这样,每个类都只有一个明确的职责,降低了类的复杂性,提高了可维护性。
2. 开放封闭原则(Open-Closed Principle, OCP)
示例:假设我们有一个支付服务类(PaymentService
),它最初只支持信用卡支付。根据开放封闭原则,我们应该设计一个可扩展的系统,以便在不修改现有代码的情况下添加新的支付方式。我们可以通过定义一个支付接口(PaymentMethod
)和多个具体的支付实现类(如CreditCardPayment
、PayPalPayment
等)来实现这一点。PaymentService
类依赖于PaymentMethod
接口,而不是具体的支付实现类。这样,当我们需要添加新的支付方式时,只需实现PaymentMethod
接口,而无需修改PaymentService
类。
3. 里氏替换原则(Liskov Substitution Principle, LSP)
示例:考虑一个父类Rectangle
(矩形)和一个子类Square
(正方形)。在Rectangle
类中,我们可能有一个setWidth
和setHeight
方法,用于设置矩形的宽和高。然而,在正方形中,宽和高必须始终相等。如果子类Square
重写了这些方法并允许宽和高设置为不同的值,那么它就违反了里氏替换原则。因为使用父类Rectangle
的地方不能透明地使用子类Square
的对象,而不会产生错误或异常。为了遵循里氏替换原则,子类应该扩展父类的功能,而不是破坏父类的行为。
4. 依赖倒置原则(Dependency Inversion Principle, DIP)
示例:在一个电商系统中,订单处理类(OrderProcessor
)可能依赖于支付服务类(PaymentService
)和物流服务类(ShippingService
)。根据依赖倒置原则,OrderProcessor
不应该直接依赖于这些具体的服务类,而应该依赖于它们的抽象(接口或抽象类)。这样,当支付服务或物流服务发生变化时,我们只需修改具体的实现类,而无需修改OrderProcessor
类。这降低了类之间的耦合度,提高了系统的可扩展性和可维护性。
5. 接口隔离原则(Interface Segregation Principle, ISP)
示例:考虑一个用户操作接口(UserOperations
),它最初包含了用户的所有操作,如创建订单、取消订单、浏览商品、管理账户等。然而,并不是所有用户都需要所有这些操作。根据接口隔离原则,我们应该将这个大接口拆分成多个小接口,每个接口只包含用户需要的部分操作。例如,我们可以将UserOperations
拆分为OrderOperations
(订单操作)、ProductOperations
(商品操作)、AccountOperations
(账户操作)等。这样,不同类型的用户只需实现他们需要的接口,减少了不必要的依赖和复杂性。
6. 迪米特法则(Law of Demeter, LOD)或最少知识原则
示例:在一个订单处理系统中,订单处理类(OrderProcessor
)可能需要访问用户信息(如支付信息和地址信息)来完成订单处理。如果OrderProcessor
直接访问用户类(User
)来获取这些信息,那么它就违反了迪米特法则。因为OrderProcessor
与用户类的内部实现细节耦合得太紧密了。为了遵循迪米特法则,我们可以引入一个中介类(如UserFacade
),它负责封装用户信息的访问逻辑。OrderProcessor
通过UserFacade
来获取用户信息,而不是直接访问User
类。这样,当User
类的实现发生变化时,只需修改UserFacade
类,而无需修改OrderProcessor
类,从而降低了类之间的耦合度。
欢迎访问我的(夏壹分享)公众号 和 博客(sanzhiwa)后缀top