Во-первых, давайте представим способ заваривания кофе и чая:
Чай
1. 把水煮沸
2. 用沸水浸泡茶叶
3. 把茶放到杯子里
кофе
1. 把水煮沸
2. 用沸水冲泡咖啡
3. 把咖啡倒进杯子
4. 加糖和牛奶
Метод заваривания, реализованный с помощью кода Python, выглядит так:
# 茶的制作方法
class Tea:
def prepare_recipe(self):
# 在下边实现具体步骤
self.boil_water()
self.brew_tea_bag()
self.pour_in_cup()
def boil_water(self):
print("Boiling water")
def brew_tea_bag(self):
print("Steeping the tea")
def pour_in_cup(self):
print("Pouring into cup")
# 咖啡的制作方法
class Coffee:
def prepare_recipe(self):
# 在下边实现具体步骤
self.boil_water()
self.brew_coffee_grinds()
self.pour_in_cup()
self.add_sugar_and_milk()
def boil_water(self):
print("Boiling water")
def brew_coffee_grinds(self):
print("Dripping Coffee through filter")
def pour_in_cup(self):
print("Pouring into cup")
def add_sugar_and_milk(self):
print("Adding Sugar and Milk")
Если вы внимательно посмотрите на код с обеих сторон, вы обнаружите, что реализация чая и кофе в основном похожа.prepare_recipe
,boil_water
,pour_in_cup
эти три метода.
问题:
Как переделать эти два класса, чтобы сделать код более лаконичным?
Сначала посмотрите на диаграмму классов двух классов:
- в каждом классе
prepare_recipe() boil_water() pour_in_cup()
метод. - в каждом классе
prepare_recipe()
Методы реализуются по-разному.
теперь поставьprepare_recipe() boil_water() pour_in_cup()
Извлекаются три метода для создания родительского классаCoffeineBeverage()
,Tea
а такжеCoffee
все удалось отCoffeineBeverage()
.
потому что каждый класс
prepare_recipe()
Способ реализации разный, т.Tea
а такжеCoffee
классы реализованы отдельноprepare_recipe()
.问题
: Итак, есть ли способprepare_recipe()
Тоже абстрактно?
В сравненииTea
а такжеCoffee
изprepare_recipe()
Метод обнаружит, что различия между ними в основном заключаются в следующем:
def prepare_recipe(self):
# 相同部分隐藏
# self.boil_water()
self.brew_tea_bag() # 差异1
#self.pour_in_cup()
def prepare_recipe(self):
# 相同部分隐藏
# self.boil_water()
self.brew_coffee_grinds() # 差异1
# self.pour_in_cup()
self.add_sugar_and_milk() # 差异2
Идея реализации здесь состоит в том, чтобы заменить два различия новыми именами методов, и результаты после замены будут следующими:
def prepare_recipe(self):
# 新的实现方法
self.boil_water()
self.brew() # 差异1 使用brew 代替 brew_tea_bag 和 brew_coffee_grinds
self.pour_in_cup()
self.add_condiments() # 差异2 Tea 不需要此方法,可以用空的实现代替
Новая диаграмма классов выглядит следующим образом:
Теперь классTea
а такжеCoffee
Нужно только реализовать конкретныеbrew()
а такжеadd_condiments()
метод. Код реализован следующим образом:
class CoffeineBeverage:
def prepare_recipe(self):
# 新的实现方法
self.boil_water()
self.brew()
self.pour_in_cup()
self.add_condiments()
def boil_water(self):
print("Boiling water")
def brew(self):
# 需要在子类实现
raise NotImplementedError
def pour_in_cup(self):
print("Pouring into cup")
def add_condiments(self):
# 这里其实是个钩子方法,子类可以视情况选择是否覆盖
# 钩子方法是一个可选方法,也可以让钩子方法作为某些条件触发后的动作
pass
# 茶的制作方法
class Tea(CoffeineBeverage):
def brew(self):
# 父类中声明了 raise NotImplementedError,这里必须要实现此方法
print("Steeping the tea")
# Tea 不需要 add_condiments 方法,所以这里不需要实现
# 咖啡的制作方法
class Coffee(CoffeineBeverage):
def brew(self):
# 父类中声明了 raise NotImplementedError,这里必须要实现此方法
print("Dripping Coffee through filter")
def add_condiments(self):
print("Adding Sugar and Milk")
шаблонный метод
Вышеупомянутая абстракция использует метод шаблона. Шаблонные методы определяют шаги алгоритма и позволяют подклассам предоставлять реализации для одного или нескольких шагов. В этом примереprepare_recipe
является шаблонным методом.
定义:
Жрецы шаблонных методов определяют скелет алгоритма в методе, откладывая при этом некоторые шаги на подклассы. Шаблонные методы позволяют подклассам переопределять определенные шаги в алгоритме без изменения структуры алгоритма.
преимущество
- Используйте шаблонные методы, чтобы максимизировать повторное использование кода
- Подклассам нужно только реализовать свои собственные методы, чтобы уменьшить связь между алгоритмом и реализацией.
Голливудские принципы
Шаблонный метод использует принцип,好莱坞原则
.
В соответствии с этим принципом компоненты более низкого уровня могут подключаться к системе, но компоненты более высокого уровня должны решать, когда использовать эти компоненты более низкого уровня.
好莱坞原则
, не звони мне, я позвоню тебе.
В приведенном выше примере CoffeeineBeverage — это высокоуровневый компонент, Coffee и Tea — низкоуровневые компоненты, и между ними не будет вызываться абстрактный класс (CoffeineBeverage).
Пример 🌰
Часть проверки формы стороннего пакета проверки формы Python wtforms использует шаблон метода шаблона. в полевом классеvalidate
метод является методом шаблона, в этом методе будет вызыватьсяpre_validate
,_run_validation_chain
,post_validate
методы для проверки формы, которые также могут быть повторно реализованы в подклассах. Конкретная реализация может относиться к следующему исходному коду.
Адрес источника:GitHub.com/WT формы/WTF…
Ссылка на ссылку
Пример в этой статье взят из "Шаблоны проектирования Head First".
Наконец, поблагодарите мою девушку за ее поддержку и терпимость, чем ❤️
Вы также можете ввести следующие ключевые слова в официальном аккаунте, чтобы получить исторические статьи:公号&小程序
| 设计模式
| 并发&协程