Python 对象工厂多次重复构造函数参数

问题描述 投票:0回答:2

在编写 python 对象工厂时,我在构造函数中遇到了 lot 参数重复。感觉不对,好像有更好的方法来使用这种模式。我不确定我是否应该用

**kwargs
替换参数,或者是否有更适合这种情况的不同设计模式。

下面是一个简化的例子。真正的代码当然更复杂,你可以看到我这样做的更多原因,但我认为这是一个合理的最小可重现示例

在这些类之外,对于API,最重要的因素是

species
subspecies
。恰好在内部,
is_salt_water
很重要,导致不同的对象,但这是内部问题。


class Fish:
    def __init__(self, species, sub_species, length, weight):    # Repeating this a lot
        self.species = species
        self.sub_species = sub_species
        self.length = length
        self.weight = weight
        self.buoyancy = self.buoyancy()

    def buoyancy(self):
        raise Exception("Do not call this abstract base class directly")


class FreshWaterFish:
    def __init__(self, species, sub_species, length, weight):    # Repeating this a lot
        self.fresh_water = True
        super().__init__(species, sub_species, length, weight)   # Repeating this a lot
    def buoyancy(self):
        self.buoyancy = 3.2 * self.weight   #totally made-up example. No real-world meaning


class SaltWaterFish:
    def __init__(self, species, sub_species, length, weight):    # Repeating this a lot
        self.fresh_water = False
        super().__init__(species, sub_species, length, weight)   # Repeating this a lot

    def buoyancy(self):
        self.buoyancy = 1.25 * self.weight / self.length  #totally made-up example. No real-world meaning

def FishFactory(self, species, sub_species, length, weight, is_salt_water = False): # Repeating this a lot
    mapper = {True : FreshWaterFish, False: SaltWaterFish}
    return mapper[is_salt_water](species, sub_species, length, weight) # Repeating this a lot
python design-patterns factory-pattern
2个回答
0
投票

诀窍是使用依赖倒置原则。与其提供具体的实现

species
sub_species
length
weight
,不如将它们封装到一个对象中并传递该对象。您几乎已经使用
Fish
类完成了该操作,但如您所见,从
Fish
继承会创建冗余参数列表。

你有一个选择是使用组合来模拟继承,这反过来又满足了依赖倒置原则。在这里,我们将

FreshWaterFish
SaltWaterFish
包裹在
Fish
类中。为了保持派生的 fish 类的多态性,我们将抽象方法分离到一个接口中。实际上,我们将行为与数据分开。

class Fish:
    def __init__(self, species, sub_species, length, weight):
        self.species = species
        self.sub_species = sub_species
        self.length = length
        self.weight = weight

class IFish:
    @abstractmethod
    def buoyancy(self):
        pass
    
    @abstractmethod
    def swim(self):
        pass

class FreshWaterFish(IFish):
    def __init__(self, fish):
        self.fish = fish
        self.fresh_water = True
        self.buoyancy() # May not be best to put behavior methods inside constructors, but just following your example

    def buoyancy(self):
        self.buoyancy = 3.2 * self.fish.weight

    def swim(self):
        print('swim swim')


class SaltWaterFish(IFish):
    def __init__(self, fish):
        self.fish = fish
        self.fresh_water = False
        self.buoyancy() # May not be best to put behavior methods inside constructors, but just following your example

    def buoyancy(self):
        self.buoyancy = 1.25 * self.fish.weight / self.fish.length

    def swim(self):
        print('swam swam')

def FishFactory(self, species, sub_species, length, weight, is_salt_water = False):
    mapper = {True : FreshWaterFish, False: SaltWaterFish}
    fish_base = Fish(species, sub_species, length, weight)
    return mapper[is_salt_water](fish_base)

在某处提供长参数列表仍然是不可避免的,但现在冗余被最小化到有意义的地方并且代码相当可扩展(假设二进制淡水/咸水是语义概括)。

使用继承时,请务必考虑“X 是 Y”关系是否不是最佳方法。是的,它在语义上是有道理的,但这种思考会在您的代码中产生实际问题。

来源:

  1. https://stackoverflow.com/a/51273196/8724072

另见:


0
投票

我不知道更好的方法,但它们可能是 首先你可以使用 *args, **kwargs 但是如果你想要编译器的帮助如果没有正确完成它会很糟糕

我只是尽量避免完全替换init

在某些情况下最好保存一个类变量(比如在这种情况下 fresh_water 对每个人都是一样的)

class FreshWaterFish:
    fresh_water = True
    def buoyancy(self):
        self.buoyancy = 3.2 * self.weight 

或者在另一个函数中获取信息,比如

class Big:
    def __init__(self, a, l, o, t, o, f, args):
        ...
        self.init()

    def init(self):
        pass

class Small(Big):
      def init(self):
          self.dragon = False

我的第二个选择是使用字典作为所有兼职参数的单个参数,所以我可以很容易地用 kwargs 混淆它,并添加像

这样的描述
def function(dictionary):
    """:param dictionary: {name:str , age:int, money:FileNotFoundError}"""
    ...

希望有帮助

© www.soinside.com 2019 - 2024. All rights reserved.