对象的工厂方法-最佳做法? [英] Factory method for objects - best practice?

查看:93
本文介绍了对象的工厂方法-最佳做法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个关于使用python从相同数据的不同形式创建类或类型的实例的最佳实践的问题.使用类方法好还是完全使用单独的函数好?假设我有一个用于描述文档大小的类. (注意:这只是一个例子.我想知道创建类实例的最佳方法,而不是描述文档大小的最佳方法.)

This is a question regarding the best practice for creating an instance of a class or type from different forms of the same data using python. Is it better to use a class method or is it better to use a separate function altogether? Let's say I have a class used to describe the size of a document. (Note: This is simply an example. I want to know the best way to create an instance of the class not the best way to describe the size of a document.)

class Size(object):
    """
    Utility object used to describe the size of a document.
    """

    BYTE = 8
    KILO = 1024

    def __init__(self, bits):
        self._bits = bits

    @property
    def bits(self):
        return float(self._bits)

    @property
    def bytes(self):
        return self.bits / self.BYTE

    @property
    def kilobits(self):
        return self.bits / self.KILO

    @property
    def kilobytes(self):
        return self.bytes / self.KILO

    @property
    def megabits(self):
        return self.kilobits / self.KILO

    @property
    def megabytes(self):
        return self.kilobytes / self.KILO

我的__init__方法采用以位表示的大小值(位和只有位,我想保持这种方式),但是可以说我有一个以字节为单位的大小值,并且我想创建我的类的实例.使用类方法是更好还是完全使用单独的函数?

My __init__ method takes a size value represented in bits (bits and only bits and I want to keep it that way) but lets say I have a size value in bytes and I want to create an instance of my class. Is it better to use a class method or is it better to use a separate function altogether?

class Size(object):
    """
    Utility object used to describe the size of a document.
    """

    BYTE = 8
    KILO = 1024

    @classmethod
    def from_bytes(cls, bytes):
        bits = bytes * cls.BYTE
        return cls(bits)

OR

def create_instance_from_bytes(bytes):
    bits = bytes * Size.BYTE
    return Size(bits)

这似乎不是问题,也许两个示例都是有效的,但是每当我需要实现这样的事情时,我都会考虑一下.很长时间以来,我一直偏爱类方法方法,因为我喜欢将类方法和工厂方法联系在一起的组织好处.同样,使用类方法保留了创建任何子类实例的能力,因此它更加面向对象.另一方面,一个朋友曾经说过如果有疑问,请执行标准库的工作",而我还没有在标准库中找到一个示例.

This may not seem like an issue and perhaps both examples are valid but I think about it every time I need to implement something like this. For a long time I have preferred the class method approach because I like the organisational benefits of tying the class and the factory method together. Also, using a class method preserves the ability to create instances of any subclasses so it's more object orientated. On the other hand, a friend once said "When in doubt, do what the standard library does" and I am yet to find an example of this in the standard library.

推荐答案

首先,大多数情况下,您认为不需要这样的东西;这表明您正在尝试将Python像Java一样对待,而解决方案是退后一步,询问为什么需要工厂.

First, most of the time you think you need something like this, you don't; it's a sign that you're trying to treat Python like Java, and the solution is to step back and ask why you need a factory.

通常,最简单的方法是仅使用带有默认/可选/关键字参数的构造函数.即使在Java中您从未用这种方式编写的情况(甚至在C ++或ObjC中重载的构造函数都会感到错误的情况)在Python中也看起来很自然.例如,size = Size(bytes=20)size = Size(20, Size.BYTES)看起来很合理.因此,从Size继承并完全不添加任何内容的Bytes(20)类,除了__init__重载看起来是合理的.这些定义起来很简单:

Often, the simplest thing to do is to just have a constructor with defaulted/optional/keyword arguments. Even cases that you'd never write that way in Java—even cases where overloaded constructors would feel wrong in C++ or ObjC—may look perfectly natural in Python. For example, size = Size(bytes=20), or size = Size(20, Size.BYTES) look reasonable. For that matter, a Bytes(20) class that inherits from Size and adds absolutely nothing but an __init__ overload looks reasonable. And these are trivial to define:

def __init__(self, *, bits=None, bytes=None, kilobits=None, kilobytes=None):

或者:

BITS, BYTES, KILOBITS, KILOBYTES = 1, 8, 1024, 8192 # or object(), object(), object(), object()
def __init__(self, count, unit=Size.BITS):

但是,有时候您要做需要工厂功能.那么,您该怎么办?好吧,通常有两种东西会被集中到工厂"中.

But, sometimes you do need factory functions. So, what do you do then? Well, there are two kinds of things that are often lumped together into "factories".

@classmethod是执行替代构造函数"的惯用方式-stdlib上有示例-itertools.chain.from_iterabledatetime.datetime.fromordinal等.

A @classmethod is the idiomatic way to do an "alternate constructor"—there are examples all over the stdlib—itertools.chain.from_iterable, datetime.datetime.fromordinal, etc.

函数是执行我不在乎实际的类是"工厂的惯用方式.查看例如内置的open函数.您知道它在3.3中返回什么吗?你关心?没有.这就是为什么它是一个函数,而不是io.TextIOWrapper.open之类的原因.

A function is the idiomatic way to do an "I don't care what the actual class is" factory. Look at, e.g., the built-in open function. Do you know what it returns in 3.3? Do you care? Nope. That's why it's a function, not io.TextIOWrapper.open or whatever.

您给出的示例似乎是一个完全合法的用例,非常清楚地适合替代构造函数" bin(如果它不适合带有额外参数的构造函数" bin).

Your given example seems like a perfectly legitimate use case, and fits pretty clearly into the "alternate constructor" bin (if it doesn't fit into the "constructor with extra arguments" bin).

这篇关于对象的工厂方法-最佳做法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆