【问题标题】:Name of Design Pattern: get class from class level设计模式名称:从类级别获取类
【发布时间】:2014-12-19 18:27:43
【问题描述】:

特别是在单元测试中,我们使用这种“设计模式”,我称之为“从类级别获取类”

frameworktest.py:

class FrameWorkHttpClient(object):
    ....

class FrameWorkTestCase(unittest.TestCase):

    # Subclass can control the class which gets used in get_response()
    HttpClient=FrameWorkHttpClient  

    def get_response(self, url):
        client=self.HttpClient()
        return client.get(url)

mytest.py:

class MyHttpClient(FrameWorkHttpClient):
    ....

class MyTestCase(FrameWorkTestCase):
    HttpClient=MyHttpClient

    def test_something(self):
        response=self.get_response()
        ...

get_response() 方法从self 获取类,而不是通过导入它。这样子类可以修改类并使用不同的HttpClient。

这个(从类级别获取类)“设计模式”的名称是什么?

这是一种“控制反转”还是“依赖注入”的方式?

【问题讨论】:

    标签: python inheritance design-patterns dependency-injection inversion-of-control


    【解决方案1】:

    您的代码与Factory method pattern 非常相似。唯一的区别是您的变体使用工厂类变量而不是工厂方法。

    【讨论】:

    • 谢谢。是的,工厂方法模式看起来非常相似。
    【解决方案2】:

    我相信这与使用 Python 特定语法实现的简单多态具有相同的目的。您可以将实例类型存储为类/子类中的“可覆盖变量”,而不是让虚拟方法返回新实例。

    这可以重写为虚拟方法(对不起,我不熟悉 Python,所以这只是伪代码)

    virtual HttpClient GetClient()
      return new FrameworkHttpClient()
    

    然后在子类中,更改方法的实现以返回不同的类型:

    override HttpClient GetClient()
      return new MyHttpClient()
    

    如果你想称之为模式,我会说它类似于Strategy GoF pattern。在您的特定情况下,被抽象出来的算法是创建特定的 HttpClient 实现。

    再三考虑——正如你所说,这确实可以看作是一个 IoC 的例子。

    【讨论】:

      【解决方案3】:

      我不完全是设计模式“大师”,但对我来说它看起来有点像模板方法模式。您正在基类中定义get_response 方法的“骨架”,并将一步(定义要使用的类)留给子类。

      如果这可以被认为是模板模式,那就是控制反转的一个例子。

      【讨论】:

        【解决方案4】:

        你想让子类决定实例化哪个类。

        这是factory method pattern 已经提供的:

        定义一个用于创建对象的接口,但让实现该接口的类决定实例化哪个类。 Factory 方法允许类将实例化推迟到子类。 (GoF)

        您通过替换父类的变量来解决相同的问题。 它有效,但您的解决方案至少有两个缺点(与经典模式相比):

        1. 您引入了时间耦合(设计气味)。客户必须以正确的顺序调用指令。 (先初始化HttpClient,然后调用get_response)
        2. 您的测试用例不是一成不变的。不可变类比可变类更简单。在我看来,测试应该总是简单的。

        【讨论】:

        • 回复“1.您引入了时间耦合(设计气味)。客户必须以正确的顺序调用指令。”这不是设计模式“工厂方法”引入的。在导入 HttpClient 之前。子类不能使用不同的 HttpClient。回复“2.你的测试用例不是一成不变的”。请解释一下。在使用工厂方法模式之前,我看不出它是如何不可变的。
        • @guetti 我不明白你的第一个回复。我的观点是,如果您使用工厂方法模式,它是不可变的。
        • HttpClient 在类级别初始化,而不是在__init__() 中。 不可能以错误的顺序调用事物,因为在实例化之前必须完全初始化类。
        猜你喜欢
        • 2017-12-24
        • 1970-01-01
        • 2020-05-25
        • 2016-06-25
        • 2017-08-02
        • 2013-06-22
        • 1970-01-01
        • 1970-01-01
        • 2021-10-16
        相关资源
        最近更新 更多