`
lushuaiyin
  • 浏览: 675264 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

设计模式之一---工厂方法模式【Factory Method模式】

 
阅读更多
在设计模式中,Factory Method模式是一种比较简单的设计模式,应用比较广泛,但也是一种比较重要的设计模式之一。在很多地方我们都会看到xxxFactory这样命名的类,那么,什么是Factory Method,为什么要用这个模式,如何用Java语言来实现该模式?

【1】基本概念

FactoryMethod是一种创建性模式,它定义了一个创建对象的接口,但是却让子类来决定具体实例化哪一个类.当一个类无法预料要创建哪种类的对象或是一个类需要由子类来指定创建的对象时我们就需要用到Factory Method 模式了.简单说来,Factory Method可以根据不同的条件产生不同的实例,当然这些不同的实例通常是属于相同的类型,具有共同的父类.Factory Method把创建这些实例的具体过程封装起来了,简化了客户端的应用,也改善了程序的扩展性,使得将来可以做最小的改动就可以加入新的待创建的类. 通常我们将Factory Method作为一种标准的创建对象的方法,当发现需要更多的灵活性的时候,就开始考虑向其它创建型模式转化。

【2】简单分析

我们先来看一下该设计模式的UML图:


上图是Factory Method 模式的结构图,让我们可以进行更方便的描述:

  1. Product: 需要创建的产品的抽象类.
  2. ConcreteProduct: Product的子类,一系列具体的产品.
  3. Creator: 抽象创建器接口,声明返回Product类型对象的Factory Method.
  4. ConcreteCreator: 具体的创建器,重写Creator中的Factory Method,返回ConcreteProduct类型的实例.

同时可以清楚的看出这样的平行对应关系: Product <====> Creator ; ConreteProduct <====> ConreteCreator

抽象产品对应抽象创建器,具体产品对应具体创建器.这样做的好处是什么呢?为什么我们不直接用具体的产品和具体的创建器完成需求呢?实际上我们也可以这样做.但通过Factory Method模式来完成,客户(client)只需引用抽象的Product和Creater,对具体的ConcreteProduct和ConcreteCreator可以毫不关心,这样做我们可以获得额外的好处:

  • 首先客户端可以统一从抽象创建器获取产生的实例,Creator的作用将client和产品创建过程分离开来,客户不用操心返回的是那一个具体的产品,也不用关心这些产品是如何创建的.同时,ConcreteProduct也被隐藏在Product后面,ConreteProduct继承了Product的所有属性,并实现了Product中定义的抽象方法,按照Java中的对象造型(cast)原则,通过ConcreteCreator产生的ConcreteProduct可以自动的上溯造型成Product.这样一来,实质内容不同的ConcreteProduct就可以在形式上统一为Product,通过Creator提供给client来访问.
  • 其次,当我们添加一个新的ConcreteCreator时,由于Creator所提供的接口不变,客户端程序不会有丝毫的改动,不会带来动一发而牵全身的灾难, 这就是良好封装性的体现.但如果直接用ConcreteProduct和ConcreteCreator两个类是无论如何也做不到这点的. 优良的面向对象设计鼓励使用封装(encapsulation)和委托(delegation),而Factory Method模式就是使用了封装和委托的典型例子,这里封装是通过抽象创建器Creator来体现的,而委托则是通过抽象创建器把创建对象的责任完全交给具体创建器ConcreteCreator来体现的.
【3】如何用java语言来实现该模式

该模式采用一个Shape(形状)的经典例子作为一个实例来展示如何实现Factory Method模式,先看下代码的结构图:


3.1首先定义一个抽象类Shape,定义两个抽象的方法.

  1. packagecom.andyidea.patterns.product;
  2. /**
  3. *Product:需要创建的产品的抽象类.
  4. *@authorAndy.Chen
  5. *
  6. */
  7. publicabstractclassShape{
  8. publicStringname;
  9. publicShape(StringaName){
  10. this.name=aName;
  11. }
  12. //绘画
  13. publicabstractvoiddraw();
  14. //擦除
  15. publicabstractvoiderase();
  16. }
3.2 定义 Shape的两个子类: Circle, Square,实现Shape中定义的抽象方法

Circle中的源码如下:

  1. packagecom.andyidea.patterns.concreteproduct;
  2. importcom.andyidea.patterns.product.Shape;
  3. /**
  4. *圆形子类(ConcreteProduct:Product的子类,一系列具体的产品.)
  5. *@authorAndy.Chen
  6. *
  7. */
  8. publicclassCircleextendsShape{
  9. publicCircle(Stringname){
  10. super(name);
  11. }
  12. @Override
  13. publicvoiddraw(){
  14. System.out.println("ItwilldrawaCircle");
  15. }
  16. @Override
  17. publicvoiderase(){
  18. System.out.println("ItwilleraseaCircle");
  19. }
  20. }
Square中的源码:

  1. packagecom.andyidea.patterns.concreteproduct;
  2. importcom.andyidea.patterns.product.Shape;
  3. /**
  4. *方形子类(ConcreteProduct:Product的子类,一系列具体的产品.)
  5. *@authorAndy.Chen
  6. *
  7. */
  8. publicclassSquareextendsShape{
  9. publicSquare(Stringname){
  10. super(name);
  11. }
  12. @Override
  13. publicvoiddraw(){
  14. System.out.println("ItwilldrawaSquare");
  15. }
  16. @Override
  17. publicvoiderase(){
  18. System.out.println("ItwilleraseaSquare");
  19. }
  20. }
3.3 定义抽象的创建器,anOperation调用factoryMethod创建一个对象,并对该对象进行一系列操作.

  1. packagecom.andyidea.patterns.creator;
  2. importcom.andyidea.patterns.product.Shape;
  3. /**
  4. *Creator:抽象创建器接口,声明返回Product类型对象的FactoryMethod.
  5. *@authorAndy.Chen
  6. *
  7. */
  8. publicabstractclassShapeFactory{
  9. protectedabstractShapefactoryMethod(StringaName);
  10. publicvoidanOperation(StringaName){
  11. Shapes=factoryMethod(aName);
  12. System.out.println("Thecurrentshapeis:"+s.name);
  13. s.draw();
  14. s.erase();
  15. }
  16. }
3.4 定义与circle和square相对应的两个具体创建器CircleFactory,SquareFactory,实现父类的methodFactory方法

CircleFactory中的源码:

  1. packagecom.andyidea.patterns.concretecreator;
  2. importcom.andyidea.patterns.concreteproduct.Circle;
  3. importcom.andyidea.patterns.creator.ShapeFactory;
  4. importcom.andyidea.patterns.product.Shape;
  5. /**
  6. *ConcreteCreator:具体的创建器,重写Creator中的FactoryMethod,
  7. *返回ConcreteProduct类型的实例.
  8. *@authorAndy.Chen
  9. *
  10. */
  11. publicclassCircleFactoryextendsShapeFactory{
  12. @Override
  13. protectedShapefactoryMethod(StringaName){
  14. returnnewCircle(aName+"(createdbyCircleFactory)");
  15. }
  16. }
SquareFactory中的源码:

  1. packagecom.andyidea.patterns.concretecreator;
  2. importcom.andyidea.patterns.concreteproduct.Square;
  3. importcom.andyidea.patterns.creator.ShapeFactory;
  4. importcom.andyidea.patterns.product.Shape;
  5. /**
  6. *ConcreteCreator:具体的创建器,重写Creator中的FactoryMethod,
  7. *返回ConcreteProduct类型的实例.
  8. *@authorAndy.Chen
  9. *
  10. */
  11. publicclassSquareFactoryextendsShapeFactory{
  12. @Override
  13. protectedShapefactoryMethod(StringaName){
  14. returnnewSquare(aName+"(createdbySquareFactory)");
  15. }
  16. }
3.5 测试类MainClient:这个客户端程序没有罗嗦的条件判断语句,也无需关心ConcreteProduct和ConcreteCreator的细节(因为这里我用anOperation封装了Product里的两个方法,所以连Product的影子也没看见,当然把Product里方法的具体调用放到客户程序中也是不错的).
  1. packagecom.andyidea.patterns.client;
  2. importcom.andyidea.patterns.concretecreator.CircleFactory;
  3. importcom.andyidea.patterns.concretecreator.SquareFactory;
  4. importcom.andyidea.patterns.creator.ShapeFactory;
  5. /**
  6. *测试设计模式类
  7. *@authorAndy.Chen
  8. *
  9. */
  10. publicclassMainClient{
  11. publicstaticvoidmain(String[]args){
  12. ShapeFactorysf1=newCircleFactory();
  13. ShapeFactorysf2=newSquareFactory();
  14. System.out.println("WelcometoAndy.ChenBlog!"+"\n"
  15. +"FactoryMethodPatterns."+"\n"
  16. +"-------------------------------");
  17. sf1.anOperation("Shape-Circle");
  18. sf2.anOperation("Shape-Square");
  19. }
  20. }
【4】程序运行结果如下:

  1. WelcometoAndy.ChenBlog!
  2. FactoryMethodPatterns.
  3. -------------------------------
  4. Thecurrentshapeis:Shape-Circle(createdbyCircleFactory)
  5. ItwilldrawaCircle
  6. ItwilleraseaCircle
  7. Thecurrentshapeis:Shape-Square(createdbySquareFactory)
  8. ItwilldrawaSquare
  9. ItwilleraseaSquare
【5】总结:用Factory Method模式创建对象并不一定会让我们的代码更短,实事上往往更长,我们也使用了更多的类,真正的目的在于这样可以灵活的,有弹性的创建不确定的对象.而且,代码的可重用性提高了,客户端的应用简化了,客户程序的代码会大大减少,变的更具可读性。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics