OOP 五大原则, 5 Principles of Object-oriented Programming

1. Single Responsibility Principle (SRP)

单一职责原则

定义

  • Every module/class/function should have single responsibility and only change for 1 reason .
  • 一个class/module 只能有一项职责,也只因为一个原因而发生改变。

优势

  • 提高reusability.
  • 提高 maintainability

示例

class SaleOrders:
    """
    A class keeps information about a sales order
    """
    # ✅, meets SRP
    def saveOrder(order: Order):
        pass

    # ❌, Violate for SRP. Because there will be different type clients to use this class 
    # and there will be different reasons to modify this class
    def exportOrderAsHtml() :
        pass

2. Open-Closed Principle (OCP)

开闭原则

定义

  • Each software entity should be open for extension, but closed for modification.
  • 一个实体(类、函数、模块等),可以不断衍生,但不经常修改。

优势

  • 提高extensibility
  • Easy to maintain and upgrade 易于维护和升级

❌ 错误示例

 """
 This design violates the OCP because if the rules change, 
 the OrderValidation class has to be modified, tested, and compiled.
 """
class OrderValidation:

    def _rule1(self, order: Order):
        pass

    def _rule2(self, order: Order):
        pass

    def _rule3(self, order: Order):
        pass

    def validate(self, order: Order):
        if order.amount > 1000:
            return self._rule1(order)

        if order.amount > 500:
            return self._rule2(order)

        return self._rule3(order)

✅ 正确示例

   """
   The new design will satisfy the OCP, 
   because if the rules change,  we can just create a new Validator class
   """
from abc import ABC, abstractmethod

class Validator(ABC):

    @abstractmethod
    def validate(self, order: Order):
        raise NotImplementedError


class Validator1(Validator):

    def validate(self, order: Order):
        pass


class Validator2(Validator):

    def validate(self, order: Order):
        pass


class Validator3(Validator):

    def validate(self, order: Order):
        pass

class OrderValidation:

    def __init__(self, validator: Validator):
        self._validator = validator

    def validate(self, order):
        return self._validator.validate(order)

3. Liskov Substitution Principle (LSP)

里氏代换原则

定义

  • Objects in a program should be replaceable with instances of their subclasses without altering the correctness of that program.
  • 子类可以替换父类,且不影响程序正确性。是开闭原则的补充。

优势

  • 提高reusability.
  • 提高 maintainability

❌ 错误示例

 """
 This design will violate LSP.
 If a client uses a reference variable of type Rectangle to call the setSize() method 
 to assign different values of height and width, then results will be different
 if the variable references to a Rectangle object than to a Square object.
 """
class Rectangle:

    def __init__(self):
        self._height = None
        self._width = None

    def set_size(self, height: int, width: int):
        self._height = height
        self._width = width

class Square(Rectangle):

    def set_size(self, height: int, width: int):
        self._height = height
        self._width = height

4. Interface Segregation Principle (ISP)

接口隔离原则

定义

  • Clients should not be forced to depend on interfaces that they do not use.
  • 解决不同的问题的时候,利用不同的接口。不要局限于单一接口。

优势

  • Reduce coupling, 降低耦合。
  • Reduce interdependency, 降低依赖。

❌ 错误示例

"""
This violates ISP because clients are forced to depend on
methods they do not use: HighWay does not use stat_engine(),
and ParkingLot does not need accelerate().
"""
class Vehicle:

    def stat_engine(self):
        pass

    def accelerate(self):
        pass

    def get_speed(self):
        pass

    def get_vehicle_type(self):
        pass

    def is_ticketed(self):
        pass

✅ 正确示例

"""
A better design is to design smaller interfaces for different types of clients
as shown in the following figure
"""
class DriverVehicle:

    def stat_engine(self):
        pass

    def accelerate(self):
        pass

class HighwayVehicle:

    def get_speed(self):
        pass

    def get_vehicle_type(self):
        pass

class ParkingLotVehicle:

    def is_ticketed(self):
        pass

5. Dependency Inversion Principle (DIP)

依赖倒转原则

定义

  • High level modules should not depend on low level modules, both should depend on abstraction.
    Also, abstraction should not depend on details, details should depend on abstractions.
  • 针对接口编程,依赖于抽象而不依赖于具体。

优势

  • Reduce coupling, 降低耦合。
  • Reduce interdependency, 降低依赖。

❌ 错误示例

"""
Making an EBookReader class to use PDFBook class is a violation of DIP because it requires to change 
the EBookReader class to read other types of e-books. 
"""
class PDFBook:

    def read(self):
        pass

class EBookReader:

    def __init__(self, pdfBook: PDFBook):
        self._pdfBook = pdfBook

✅ 正确示例

"""
A better design is to let EBookReader  use an interface EBook and let PDFBook and other types of
e-book classes implement EBook. Now adding or 
changing e-book classes will not require any change to EBookReader class.
"""
from abc import abstractmethod, ABC

class EBook(ABC):

    @abstractmethod
    def read(self):
        raise NotImplementedError

class PDFBook(EBook):

    def read(self):
        pass

class TXTBook(EBook):

    def read(self):
        pass

class EBookReader:

    def __init__(self, eBook: EBook):
        self._eBook = eBook

    def read(self):
        self._eBook.read()

参考资料

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容