Factory Method
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 341.25pt; HEIGHT: 191.25pt" o:ole="" type="#_x0000_t75"><imagedata o:title="" src="file:///C:/DOCUME~1/Sarkuya/LOCALS~1/Temp/msohtml1/01/clip_image001.png"></imagedata></shape>
public interface Creator {
public void factoryMethod();
public void anOperation();
}
public class ConcreteCreator implements Creator {
public void factoryMethod() {
return new ConcreteProduct();
}
}
Client端的使用:
List 1
Creator factory = new ConcreteCreator();
Product product = factory.factoryMethod();
解析:
Ø 不使用设计模式时,代码如下:
Product product = new ConcreteProduct(); // A 或
ConcreateProduct product = new ConcreteProduct(); // B
Ø A直接违反了依赖倒转原则:product将依赖于具体的ConcreteProduct类。更有甚者,B直接产生了一个具体产品,造成以后使用此product的对象也不得不依赖于具体的ConcreteProduct类。这是非常容易被疏忽的地方。
Ø 此模式体现了一个模式思想:将可变因素封装起来,并向外界提供一个不变的接口。上例中,所有的可变因素都抽象、封装到一个Creator的接口中,而Product的产生只依赖于此接口的factoryMethod()方法。
Ø 在List 1中,我们的目标是对于任何一个实现了Product接口的 product,应当都由实现了Creator接口的factory来自动产生,其代码应恒为:
Product product = factory.factoryMethod()。
这样,即使以后出了新的产品,这条语句都不会改变。这正是开-闭原则的具体实现。而要做到这一点,我们必须使用
Creator factory = new ConcreteCreator();
的语句。这就出现了一个硬编码的new语句,而且new的后面直接绑定了一个具体的ConcreteCreator类,在以后出现新的product后,还得必须在此处修改这个相应的ConcreteCreator类,是否违反了开-闭原则?
Ø 是的,部分违反了开-闭原则。对“软件应当对扩展开放”来讲,它做到了,但违反了“对修改关闭”。这是因为,在Java中,任何对象都必须通过new来创建,而且不能通过new来创建接口或抽象类,即使运用了各种设计模式之后依旧不可避免。因此,对new ConcreteCreator(),我们做不了其他文章。但别忘了,我们的目标是要得到一个Product,而不是一个ConcreteCreator,这个ConcreteCreator对象是为了帮助我们灵活地获得Product而额外增加的对象。
Ø 这种方式让我们获得几个好处:一是Product product = factory.factoryMethod();的目标代码不会改变;二是在生成具体的ConcreteCreator时,我们并未立即生成Product,只有在调用factory.factoryMethod()的方法后才产生Product。这种解耦是我们借以实现Product product = factory.factoryMethod();的重要保障;三是Creator factory = new ConcreteCreator();体现了里氏替换原则:任何基类可以出现的地方,子类一定可以出现。通过这种替换,我们做到了灵活与不变相统一:我们可以指定不同的工厂,却可以使用相同的代码生成不同的产品。四是对于Creator factory来讲,由于它不负责生成具体的产品,因此它没必要“知道”Client需要得到什么要的产品,以及应该如何生成这种产品。它把这项工作交给实现了其接口的ConcreteCreator来完成,从而保证了该类的纯洁性与粗颗粒度。五是我们可以把具体工厂的类或实例,甚至是相应的字符串以参数的形式传入实现了Creaotr接口的某个类,让其自己指派具体的工厂类,从而将ConcreteCreator这个可变的因素再次封装起来。
Ø 这是一种典型的delegation:委派他人完成细节工作,自己大可不必事事躬亲。自己不瞎忙,还可让他人人尽其才,物尽其用。