Python作为一种动态类型化语言,如何使其不必使用抽象类/继承



我在python中查找了设计模式,在一些文章中看到了以下句子:

";我们在不使用继承的情况下实现了抽象工厂,主要是因为Python是一种动态类型的语言,因此不需要抽象类">

代码示例:

class Dog:
"""One of the objects to be returned"""
def speak(self):
return "Woof!"
def __str__(self):
return "Dog"

class DogFactory:
"""Concrete Factory"""
def get_pet(self):
"""Returns a Dog object"""
return Dog()
def get_food(self):
"""Returns a Dog Food object"""
return "Dog Food!"

class PetStore:
""" PetStore houses our Abstract Factory """
def __init__(self, pet_factory=None):
""" pet_factory is our Abstract Factory """
self._pet_factory = pet_factory

def show_pet(self):
""" Utility method to display the details of the objects retured by the DogFactory """
pet = self._pet_factory.get_pet()
pet_food = self._pet_factory.get_food()
print("Our pet is '{}'!".format(pet))
print("Our pet says hello by '{}'".format(pet.speak()))
print("Its food is '{}'!".format(pet_food))

#Create a Concrete Factory
factory = DogFactory()
#Create a pet store housing our Abstract Factory
shop = PetStore(factory)
#Invoke the utility method to show the details of our pet
shop.show_pet()

我理解我提供的例子,但我不明白这句话,我看到了很多其他例子,使用继承和抽象类(例如:本例中的抽象工厂(在python中实现设计模式,就像几乎所有其他语言(如java(一样。

如果能用代码示例解释一下这句话,以及这两种方法(有抽象类/接口/继承和没有抽象类/界面/继承(是如何不同的,我将不胜感激。

编辑:

问题:具体地说,我想通过说明如果使用继承/接口来实现给定示例的相同功能,那么代码示例(抽象工厂(会是什么样子,来了解动态类型是如何使生命更容易并补偿上述代码示例中继承/接口的使用的。

谢谢。

这里的关键是"PetFactory";。在上述代码中;PetFactory";。但从概念上讲,在实践中有一种";"接口";,我将称之为";PetFactory";。A";PetFactory";必须具有函数get_petget_food

如果一个人要写一个新的";PetFactory";,不管他们是否在头脑中命名它,他们都必须识别这个接口及其需求。

事实上,它没有真名,这使得人们更难识别它的存在,也更难理解它的存在(当"接口"只是你正在使用的许多东西中的一个时,这就变得更加重要了(。

但除此之外,为了确定";PetFactory";必须通过多个函数进行跟踪。在这种情况下,这并不太难,但有了更多的功能,它会很快变得复杂。

相反,可以使用继承并按照以下方式进行操作:

class PetFactory():
def get_pet(self):
"""returns a pet"""
pass
def get_food(self):
"""returns a string defining the pet's food"""
pass
class DogFactory(PetFactory):
def get_pet(self):
"""Returns a Dog object"""
return Dog()
def get_food(self):
"""Returns a Dog Food object"""
return "Dog Food!"

从技术的角度来看,添加这个类确实没有任何作用。但从概念上讲;PetFactory";现在很明显,它的要求很明确,并且有了一个技术名称。


随着PEP3119的实现,python现在也有了形式抽象基类。使用这些,新代码看起来像这样:

from abc import ABC, abstractmethod
class PetFactory(ABC):
@abstractmethod
def get_pet(self):
"""returns a pet"""
pass
@abstractmethod
def get_food(self):
"""returns a string defining the pet's food"""
pass
class DogFactory(PetFactory):
def get_pet(self):
"""Returns a Dog object"""
return Dog()
def get_food(self):
"""Returns a Dog Food object"""
return "Dog Food!"

这样做的好处是,它清楚地标记了PetFactory类的目的,并强制任何子类在实例化之前实现所有抽象方法。它还允许进行类型检查:isinstance(PetFactory)

如果必须用静态类型语言编写此代码,他们可能会编写一个名为PetFactory的基类,其中包含两个函数get_petget_food

但在动态类型语言中,函数(在本例中为PetStore(...)(并不关心其参数的类型。相反,它使用";鸭子打字;

这个词来自一句谚语"如果它像鸭子一样走路,像鸭子一样嘎嘎叫,那么它一定是鸭子。"(还有其他变体(。

Duck类型是一个与动态类型相关的概念,其中对象的类型或类不如它定义的方法重要。当您使用duck类型时,您根本不检查类型。相反,您检查给定方法或属性的存在。*

与动态类型语言的许多方面一样,它给了您更多的自由,但使事情不那么有组织。您不需要从特定的类继承或定义接口,但这也使出错和增加运行时错误变得更容易。

相关内容

最新更新