设计原则——开闭原则

1.全称

  • open close principle
  • 缩写为:COP

2.解释

  • 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

3.实例

1.场景:购买衣服,根据某些要求挑选符合的服装
from abc import ABC, abstractmethod
from enum import Enum


class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3


class Size(Enum):
    SMALL = 1
    MEDIUM = 2
    LARGE = 3


class Product:
    def __init__(self, name, color, size):
        self.name = name
        self.color = color
        self.size = size


class ProductFilter:
    @staticmethod
    def filter_by_color(products: [Product], color):
        for p in products:
            if p.color == color:
                yield p

    @staticmethod
    def filter_by_size(products: [Product], size):
        for p in products:
            if p.size == size:
                yield p


if __name__ == '__main__':
    p1 = Product("衬衫", Color.RED, Size.MEDIUM)
    p2 = Product("牛仔裤", Color.BLUE, Size.MEDIUM)
    p3 = Product("帽子", Color.RED, Size.LARGE)

    product_list = [p1, p2, p3]
    result = ProductFilter.filter_by_color(product_list, Color.RED)
    for r in result:
        print(r.name)
2.问题
  • 目前规则实现了,按照颜色、尺寸去挑选衣服
  • 如果需要新增一个按照颜色和尺寸同时挑选,此时就需要修改ProductFilter这个类,违背了开闭原则的初衷
3.优化
  • 将挑选规则抽离出来,形成一个抽象类,这样一来,需要增加挑选规则时,只需要继承抽象类,并具体实现其匹配规则即可,不会影响原有的匹配规则
  • 符合开闭原则
from abc import ABC, abstractmethod
from enum import Enum


class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3


class Size(Enum):
    SMALL = 1
    MEDIUM = 2
    LARGE = 3


class Product:
    def __init__(self, name, color, size):
        self.name = name
        self.color = color
        self.size = size


class Specification(ABC):
    @abstractmethod
    def is_satisfied(self, item):
        pass

    def __and__(self, other):
        # c_spec = ColorSpecification(color=Color.RED)
        # s_spec = SizeSpecification(size=Size.MEDIUM)
        # c_spec &  s_spec   ----->   AndSpecification(c_spec, s_spec)
        return AndSpecification(self, other)

    def __or__(self, other):
        return AnySpecification(self, other)


class Filter(ABC):
    @abstractmethod
    def filter(self, items, spec):
        pass


class ColorSpecification(Specification):
    def __init__(self, color):
        self.color = color

    def is_satisfied(self, item: Product):
        return item.color == self.color


class SizeSpecification(Specification):
    def __init__(self, size):
        self.size = size

    def is_satisfied(self, item: Product):
        return item.size == self.size


# 增加一个根据颜色和尺码挑选的规则
class ColorAndSizeSpecification(Specification):
    def __init__(self, color, size):
        self.color = color
        self.size = size

    def is_satisfied(self, item: Product):
        return item.size == self.size and item.color == self.color


# 组合多个挑选规则,多个规则必须同时满足
class AndSpecification(Specification):
    def __init__(self, *args):
        self.specs = args

    def is_satisfied(self, item: Product):
        return all(map(lambda spec: spec.is_satisfied(item), self.specs))


# 组合多个挑选规则,多个规则满足其一即可
class AnySpecification(Specification):
    def __init__(self, *args):
        self.specs = args

    def is_satisfied(self, item: Product):
        return any(map(lambda spec: spec.is_satisfied(item), self.specs))


class BetterFilter(Filter):
    def filter(self, items: [Product], spec: Specification):
        for item in items:
            if spec.is_satisfied(item):
                yield item


if __name__ == '__main__':
    p1 = Product("衬衫", Color.RED, Size.MEDIUM)
    p2 = Product("牛仔裤", Color.BLUE, Size.MEDIUM)
    p3 = Product("帽子", Color.RED, Size.LARGE)
    product_list = [p1, p2, p3]

    bf = BetterFilter()
    cs_spec = ColorAndSizeSpecification(color=Color.RED, size=Size.MEDIUM)
    result = bf.filter(items=product_list, spec=cs_spec)
    for r in result:
        print(r.name, '-------->', r.color)

    c_spec = ColorSpecification(color=Color.RED)
    s_spec = SizeSpecification(size=Size.MEDIUM)

    print('---------------------------And组合-------------------')
    and_spec = AndSpecification(c_spec, s_spec)
    result = bf.filter(items=product_list, spec=and_spec)
    for r in result:
        print(r.name, '-------->', r.color)

    print('---------------------------Or组合-------------------')
    and_spec = AnySpecification(c_spec, s_spec)
    result = bf.filter(items=product_list, spec=and_spec)
    for r in result:
        print(r.name, '-------->', r.color)

    print('---------------------------__and__-------------------')
    sc_spec = c_spec & s_spec
    result = bf.filter(items=product_list, spec=sc_spec)
    for r in result:
        print(r.name, '-------->', r.color)

    print('---------------------------__or__-------------------')
    sc_spec = c_spec | s_spec
    result = bf.filter(items=product_list, spec=sc_spec)
    for r in result:
        print(r.name, '-------->', r.color)
衬衫 --------> Color.RED
---------------------------And组合-------------------
衬衫 --------> Color.RED
---------------------------Or组合-------------------
衬衫 --------> Color.RED
牛仔裤 --------> Color.BLUE
帽子 --------> Color.RED
---------------------------__and__-------------------
衬衫 --------> Color.RED
---------------------------__or__-------------------
衬衫 --------> Color.RED
牛仔裤 --------> Color.BLUE
帽子 --------> Color.RED
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值