开闭原则
2023-02-26 本文已影响0人
木叶苍蓝
前言:
开闭原则的指导思想是——代码对功能扩展开放的同时应对修改关闭。我们在开发过程中,不要指望需求能从一开始就能完全确定,这是非常不切实际的想法。既然需求是一定会变化的,那么我们就应该把需求变化作为一种常态来处理,将代码设计的相对更加易扩展,易维护。在工作中的很多时候,开发与产品经理之间的主要矛盾就是,经常变化的需求与不能变化的代码之间的矛盾。
概述
开闭原则的关键在于抽象,将代码中可能会经常发生变化的部分封装成接口或抽象类(注意:Python中没有类似于 JAVA语言中接口的概念),这样当有新的需求或需求发生变化时,就可以对现有代码进行扩展以适应新的情况,不至于整个推到重做。只要从项目开发之初就遵循开发封闭原则,那么写出灵活,易扩展和易维护代码就不难做到。简言之,应尽量通过扩展实现变化而不是通过修改。
适用场景:
- 需求变化,代码升级或维护时,不应修改原有的代码而是应通过扩展实现。
- 将可能经常发生变化的部分抽象,是实现开闭原则的重要手段。但应注意不可滥用抽象,正确的做法是只将经常变化的部分抽象。
场景
以生活中书店售书的场景为例,原来只按照原价销售小说,现在由于经济下滑,书店为了生存开始打折销售:所有50元以上的书 8 折销售,其他 9 折销售,符合开闭原则的代码如下:
from abc import ABCMeta, abstractmethod
class Book(object):
__metaclass__ = ABCMeta
def __init__(self, name, price, author):
self.name = name
self.price = price
self.author = author
def getName(self):
return self.name
def getAuthor(self):
return self.author
@abstractmethod
def getPrice(self):
pass
def get_book_info(self):
return "Book name is %s Price is %s Author is %s" % (self.getName(), self.getPrice()/100.0, self.getAuthor())
class NormalBook(Book):
def getPrice(self):
return self.price
根据需求描述可知,书的价格会因外部经济环境变化而变化,所以在代码设计之初将抽象类Book 中获取书价格的方法 getPrice 置为抽象方法,抽象类外部 NormalBook 类实现原价售书,CheapBook 类实现打折售书。根据开闭原则,为解决书价格经常变化的场景,代码中增加一个子类 cheapBook 重写抽象父类 Book 中的 getPrice 方法,而不是直接在原 NormalBook 类上做修改。
class cheapBook(Book):
def getPrice(self):
if self.price > 5000:
return self.price * 0.8
else:
return self.price * 0.9
class BookStore():
def __init__(self, BookObj):
self.book_list = []
self.book_list.append(BookObj("西游记", 3000, "吴承恩"))
self.book_list.append(BookObj("三国演义", 6000, "罗贯中"))
self.book_list.append(BookObj("红楼梦", 8000, "曹雪芹"))
def sell(self, book):
print("Sell info {}".format(book.get_book_info()))
if __name__ == "__main__":
book_store = BookStore(NormalBook)
for book in book_store.book_list:
book_store.sell(book)
print("#" * 20)
book_store = BookStore(cheapBook)
for book in book_store.book_list:
book_store.sell(book)
对扩展开放,对修改关闭宾补意味着不作任何修改,需求的变化往往是底层模块的变更倒逼高层模块的逐步解耦,以实现代码灵活性,可扩展性,可维护性的目标。
注意事项:
- 需求变化的实现是通过新增加代码来完成的,不是通过修改现有代码完成的。
- 只对代码中可能频繁变化的部分抽象,当需求变化时可以根据实际情况重新派生一个实现类进行扩展