шаблон проектирования python - шаблон метода шаблона

задняя часть Python алгоритм Шаблоны проектирования

Во-первых, давайте представим способ заваривания кофе и чая:

Чай

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эти три метода.

问题:Как переделать эти два класса, чтобы сделать код более лаконичным?

Сначала посмотрите на диаграмму классов двух классов:

2bd637fbc0532bd0bafbf861005fabd3.png

  1. в каждом классеprepare_recipe() boil_water() pour_in_cup()метод.
  2. в каждом классеprepare_recipe()Методы реализуются по-разному.

теперь поставьprepare_recipe() boil_water() pour_in_cup()Извлекаются три метода для создания родительского классаCoffeineBeverage(),Teaа такжеCoffeeвсе удалось отCoffeineBeverage().

ce3e56409c313d4ce42e9878f3b5c8f4.png

потому что каждый класс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 不需要此方法,可以用空的实现代替

Новая диаграмма классов выглядит следующим образом:

bff9cea3d8f8226b6a9bb29c1deb8d88.png

Теперь класс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является шаблонным методом.

定义:Жрецы шаблонных методов определяют скелет алгоритма в методе, откладывая при этом некоторые шаги на подклассы. Шаблонные методы позволяют подклассам переопределять определенные шаги в алгоритме без изменения структуры алгоритма.

преимущество

  1. Используйте шаблонные методы, чтобы максимизировать повторное использование кода
  2. Подклассам нужно только реализовать свои собственные методы, чтобы уменьшить связь между алгоритмом и реализацией.

Голливудские принципы

Шаблонный метод использует принцип,好莱坞原则.

好莱坞原则, не звони мне, я позвоню тебе.

好莱坞原则
В соответствии с этим принципом компоненты более низкого уровня могут подключаться к системе, но компоненты более высокого уровня должны решать, когда использовать эти компоненты более низкого уровня.

В приведенном выше примере CoffeeineBeverage — это высокоуровневый компонент, Coffee и Tea — низкоуровневые компоненты, и между ними не будет вызываться абстрактный класс (CoffeineBeverage).

Пример 🌰

Часть проверки формы стороннего пакета проверки формы Python wtforms использует шаблон метода шаблона. в полевом классеvalidateметод является методом шаблона, в этом методе будет вызыватьсяpre_validate,_run_validation_chain,post_validateметоды для проверки формы, которые также могут быть повторно реализованы в подклассах. Конкретная реализация может относиться к следующему исходному коду.

Адрес источника:GitHub.com/WT формы/WTF…

Ссылка на ссылку


Пример в этой статье взят из "Шаблоны проектирования Head First".

Наконец, поблагодарите мою девушку за ее поддержку и терпимость, чем ❤️

Вы также можете ввести следующие ключевые слова в официальном аккаунте, чтобы получить исторические статьи:公号&小程序 | 设计模式 | 并发&协程