工厂class

就我个人而言,我从来没有理解过工厂类的想法,因为直接实例化一个对象似乎更为有用。 我的问题很简单,在什么情况下使用工厂类模式是最好的select,什么原因,以及一个好的工厂类是什么样的?

这里的想法是关注的分离:如果使用该对象的代码也有足够的信息来实例化它,则不需要工厂。 但是,如果有一些逻辑或configuration涉及到您不希望让API用户考虑(或混淆),则可以在工厂中隐藏所有这些(并将其封装起来以供再次使用)。

以下是一个示例:您想访问Google App Engine提供的其中一项服务。 相同的代码应该在开发环境(其中有两个版本,主从兼容)和完全不同的本地开发环境中工作。 Google不想告诉你他们内部基础设施的内部运作情况,而且你也不想知道。 所以他们所做的就是提供接口和工厂(这些接口的几个实现可供工厂select,你甚至不需要知道)。

这是来自我的代码库的真正的现场工厂。 它被用来生成一个样本类,它知道如何从一些数据集中获取数据(它最初是用C#编写的,所以请原谅任何java的虚拟)

class SamplerFactory { private static Hashtable<SamplingType, ISampler> samplers; static { samplers = new Hashtable<SamplingType, ISampler>(); samplers.put(SamplingType.Scalar, new ScalarSampler()); samplers.put(SamplingType.Vector, new VectorSampler()); samplers.put(SamplingType.Array, new ArraySampler()); } public static ISampler GetSampler(SamplingType samplingType) { if (!samplers.containsKey(samplingType)) throw new IllegalArgumentException("Invalid sampling type or sampler not initialized"); return samplers.get(samplingType); } } 

这里是一个示例用法:

 ISampler sampler = SamplerFactory.GetSampler(SamplingType.Array); dataSet = sampler.Sample(dataSet); 

正如你所看到的那样,代码并不多,甚至可能更短,更快

 ArraySampler sampler = new ArraySampler(); dataSet = sampler.Sample(dataSet); 

比使用工厂。 那为什么我还要打扰? 那么,有两个基本的原因,即相互build立:

  1. 首先,代码的简单性和可维护性。 假设在调用代码中, enum是作为参数提供的。 即如果我有一个方法需要处理的数据,包括采样,我可以写:

     void ProcessData(Object dataSet, SamplingType sampling) { //do something with data ISampler sampler = SamplerFactory.GetSampler(sampling); dataSet= sampler.Sample(dataSet); //do something other with data } 

    而不是像这样更麻烦的构造:

     void ProcessData(Object dataSet, SamplingType sampling) { //do something with data ISampler sampler; switch (sampling) { case SamplingType.Scalar: sampler= new ScalarSampler(); break; case SamplingType.Vector: sampler= new VectorSampler(); break; case SamplingType.Array: sampler= new ArraySampler(); break; default: throw new IllegalArgumentException("Invalid sampling type"); } dataSet= sampler.Sample(dataSet); //do something other with data } 

    请注意,这个怪物应该写每一次我需要我一些抽样。 你可以想象,改变它有多么有趣,比方说,我向ScalarSampler构造函数添加了一个参数,或者添加了一个新的SamplingType 。 现在这个工厂只有三个选项,想象一下有20个实现的工厂。

  2. 其次,这是代码的解耦。 当我使用工厂时,调用代码不知道或者不需要知道一个名为ArraySampler的类甚至存在。 这个类甚至可以在运行时解决,而且呼叫站点不会更聪明。 因此,我可以随意更改ArraySampler类,包括但不限于直接删除类,例如,如果我决定ScalarSampler应该用于数组数据。 我只需要改变这一行

     samplers.put(SamplingType.Array, new ArraySampler()); 

     samplers.put(SamplingType.Array, new ScalarSampler()); 

    它会神奇的工作。 我不需要改变调用类中的一行代码,这个代码的数量可以达到几百个。 实际上,工厂使我能够控制采样的内容和采样方式,而且任何采样更改都可以有效地封装在与系统其余部分接口的单个​​工厂类中。

就我个人而言,当运行时接口的实现未知或者可以dynamic化时,我使用工厂模式。

这意味着作为一个开发人员,我的工作是针对对象实例的已知接口,但我并不关心实现如何工作。

拿,例如。 您可以使用工厂模式为您提供数据库中的对象。 您不关心该数据库是平面文件,本地/单一用户数据库,服务器数据库还是networking资源,只是工厂可以生成和pipe理这些对象。

我讨厌为每种情况编写实现:P

从Joshua Bloch的有效的Java书中,部分由我重写:

1)与构造函数不同,静态工厂方法( SFM )具有名称。

 public static ComplexNumber one () { return new ComplexNumber(1, 0); } public static ComplexNumber imgOne () { return new ComplexNumber(0, 1); } public static ComplexNumber zero () { return new ComplexNumber(0, 0); } 

2)每次调用SFM不需要创build一个新的对象

 public static Boolean valueOf(boolean b) { return b ? Boolean.TRUE : Boolean.FALSE; } 

3) SFM可以返回其返回types的任何子types的对象。

4) SFM减less了创build参数化types实例的冗长度。

 public static <K, V> HashMap<K, V> newInstance() { return new HashMap<K, V>(); } Map<String, List<String>> m = HashMap.newInstance(); 

为了补充Thilo的回答,让我们假设你有一个只有布尔型作为构造函数的对象:每次构build一个对象将是一个完全的浪费,因为它只有两个可能的值。

在这种情况下,您可以创build静态工厂方法。 Java的Boolean类就是一个例子: Boolean.valueOf()

工厂本身并没有如此轻松地展示其美丽。 例如,当你看到真正的好处时,如果你想使用装饰模式,直接实例化一个对象可能会增加一些额外的耦合到你的代码。 正如OOP老师所说,耦合是不好的:)所以如果你要实例化装饰的对象,并不想增加耦合,那么你可以使用工厂。

您可以参考维基百科 ,但大多数devise模式的基本概念是引入一些抽象以实现更好的可维护性和/或可重用性。 工厂方法模式也不例外,它是从代码中抽象出创build的复杂性。

对于简单的情况,似乎没有必要使用工厂模式,一个简单的new就足够了。 但是当你需要更多的灵活性或function时,这种模式可能会有帮助。

例如,除非需要新的实例,静态工厂的valueOf(boolean)通常比new Bealean(boolean)更好,因为它避免了创build不必要的对象。 工厂方法模式也被称为虚拟构造器 。 众所周知,多态是OOP的关键特征之一,而构造函数不能是多态的,这种缺点可以通过工厂方法模式来克服。

实质上,直接实例化一个对象(通常是通过new )几乎不是一个具体的实现 ,而工厂方法模式通过一个稳定的 接口 (不限于Java中的interface )屏蔽了一个易失的 实现 ,而是在一些抽象的背后推动对象创build的逻辑以确保更可维护和可重用的代码。

总而言之,要充分理解工厂方法模式和其他devise模式的好处,需要掌握面向对象的本质,包括数据抽象 ,多态抽象和SOLID原则。