天天看点

设计模式:(1)工厂方法模式(Factory Method)

设计模式:(1)工厂方法模式(Factory Method)

介绍第一个设计模式前,我想给大家分享一下关于设计模式的分类。

“每一个设计模式描述了在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复的劳动”。这就是使用设计模式的意义。设计模式的核心在于提供了一类问题的解决方案和总结的精化,使得人们可以简单方便的使用成功的设计和体系结构。

设计模式一般有4个要素:

模式名称(pattern name)。一个助记符号,他用一两个词描述模式的问题、解决方案和效果。

问题(problem)。问题描述了应该在何时使用设计模式。

解决方案(solution)。解决方案描述了设计的组成成分,他们之间的相互关系及各自的职责和协作方式。

效果(consequences)。效果描述了使用设计模式的效果及使用设计模式权衡的问题。尽管效果并不是设计模式要素的关键,但是用效果来评价设计模式的使用代价和好处至关重要。效果包括系统的灵活性、扩充性和可移植性。

按照设计模式的使用目的可将其分为三大类,如下图所示:

设计模式:(1)工厂方法模式(Factory Method)

创建型模式与对象的创建有关,结构型模式处理类和对象的组合,行为模式对类或对象怎样交互怎样分配职责进行描述。

创建型模式(Creational Pattern)抽象了实例化过程,它们帮助一个系统独立于如何创建、组合和表示它的那些对象。创建型模式分为类的创建模式和对象的创建模式两种:

类的创建模式:类的创建模式使用继承关系,把类的创建延迟到子类,从而封装了客户端将得到哪些具体类的信息,并且隐藏了这些类的实例是如何被创建和放在一起的。

对象的创建模式:对象的创建模式把对象的创建过程动态地委派给另一个对象,从而动态地决定客户端将得到哪些具体类的实例。

设计模式的实现其实就是解决六大设计模式基本原则中提出的问题,在阅读下面分享的内容的时候如果有人对设计模式的六大基本原则比较陌生可以翻看公众号的历史进行查看。如果对设计模式的六大基本原则已经很熟悉的朋友请留意我在分享的第一个设计模式中所涉及的设计原则。

第一个设计模式:工厂方法(Factory Method)

意图:定义一个用于创建对象的抽象类Factory,让具体的ConcreteFactory子类决定实例化哪一个IProduct类型的产品,该模式使得一个类(即IProduct)的实例化延迟到其子类(即Product)。

类型:类创建型模式

结构UML图:

设计模式:(1)工厂方法模式(Factory Method)

其中:

  • IProduct 定义工厂方法所创建的对象的接口(抽象类或者接口)。
  • Product 定义具体实现的产品。
  • Factory 抽象工厂类用于规范化所有创建具体产品的工厂类的行为,其中声明一个创建产品的方法,该方法返回一个IProduct类型的对象。Factory 也可以定义一个默认的工厂方法,它返回一个默认的具体Product对象。
  • ConcreteFactory 重定义工厂方法以返回一个具体的Product对象。

模式标准代码:

interface IProduct {

       public void productMethod();

}

 

class Product implements IProduct {

       public void productMethod() {

              System.out.println("具体产品");

       }

}

 

abstract class Factory {
       public abstract IProduct  createProduct();
       public void anOperation(){
         System.out.println("默认做一点儿事情吧!");
       }
  }

 

class ConcreteFactory extends Factory {
       public IProduct  createProduct() {
        return new Product();
       }
  }

 

public class Client {

       public static void  main(String[] args) {

              Factory factory = new  Factory();

              IProduct product =  factory.createProduct();

              product.productMethod();

       }

}

           

通过分析工厂方法的类图和示例代码可以得出:

首先通过工厂方法模式实现了对复杂对象的生成过程的隐蔽,这样使调用者只关心生成的对象而不必关心具体的对象的生成过程。所以可以在任何需要生成复杂对象的地方,使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂方法模式,而简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂方法模式。如果使用工厂方法模式,就需要引入一个工厂类,会增加系统的复杂度。

其次,工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。

再次,由于工厂模式是依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性比较好即遵循了“开闭原则”,也就是说,当需要系统有比较好的扩展性时,可以考虑工厂方法模式,不同的产品用不同的实现工厂来组装。

工厂方法模式是简单工厂模式(该模式比较简单不做介绍)的衍生,解决了许多简单工厂模式的问题。

此外需要提及的是,上面的总结同样适用于简单工厂模式和抽象工厂模式,抽象工厂模式将会在未来的分享中提及。

应用场景例子:

下面我们就以生产泡面的过程为例子说明工厂方发模式的优点。生产泡面的过程主要分为:生产面条,生产调料,生产包装盒和生产餐具等部分。如果不用工厂方法模式:

class Noodles {

   public void getNoodles() {

      System.out.println("生产面条!");

   }

}




class Seasoning {

   public void getSeasoning() {

      System.out.println("生产调料!");

   }

}




class Box {

   public void getBox() {

      System.out.println("生产包装盒!");

   }

}




class Tableware {

   public void getTableware() {

      System.out.println("生产餐具!");

   }

}




interface IInstantNoodles {

   public void showInstantNoodles();

}




class InstantNoodles implements IInstantNoodles {

   private Noodles noodles;

   private Seasoning seasoning;

   private Box box;

   private Tableware tableware;

   public InstantNoodles(Noodles noodles, 

        Seasoning  seasoning, Box box,

        Tableware  tableware) {

      this.noodles = noodles;

      this.seasoning = seasoning;

      this.box = box;

      this.tableware = tableware;

   }

   public void showInstantNoodles() {

      noodles.getNoodles();

      seasoning.getSeasoning();

      box.getBox();

      tableware.getTableware();

   }

}




public class Client {

   public static void  main(String[] args) {

      Noodles  noodles = new Noodles();

      Seasoning  seasoning = new Seasoning();

      Box  box = new Box();

      Tableware  tableware = new Tableware();

      IInstantNoodles  instantNoodles = 

           new InstantNoodles(noodles, 

                 seasoning,box,  tableware);

      instantNoodles.showInstantNoodles();

   }

}

           

可以看到,调用者为了获取泡面还需要另外实例化面条、调料,包装盒和餐具而这些方便面的的组成成分与调用者无关的,严重违反了迪米特法则,耦合度太高。并且非常不利于扩展。另外,本例中方便面的组成成分还是比较具体的,在实际应用中,可能这些产品的组成成分也都是抽象的,调用者根本不知道怎样组装产品。假如使用工厂方法的话,整个架构就显得清晰了许多。

/**注意:泡面的组成成分类和上面的代码中的类相同,泡面接口和其实现类也相同**/

abstract class  InstantNoodlesFactory {

   public abstract IInstantNoodles productInstantNoodles();

}

 

class InstantNoodlesConcreteFactory extends InstantNoodlesFactory {

   @Override

   public IInstantNoodles productInstantNoodles() {

      Noodles  noodles = new Noodles();

      Seasoning  seasoning = new Seasoning();

      Box  box = new Box();

      Tableware  tableware = new Tableware();

      IInstantNoodles  instantNoodles 

        =  new  InstantNoodles(noodles, seasoning,

                      box, tableware);

      return instantNoodles;

   }

}

 

publicclass Client {

   public static void  main(String[] args) {

      InstantNoodlesFactory  instantNoodleFactory 

                = new  InstantNoodlesConcreteFactory();

      IInstantNoodles  instantNoodles 

                = instantNoodleFactory.productInstantNoodles();

      instantNoodles.showInstantNoodles();

   }

}

           

使用工厂方法后,调用端的耦合度大大降低了。并且对于工厂来说,是可以扩展的,以后如果想组装其他的泡面,只需要再增加一个工厂类的实现就可以。无论是灵活性还是稳定性都得到了极大的提高。

---------------

这个模式也就写到这里了,我的理解就是这样。并且我感觉有些饿了,还好有工厂方法模式生产泡面,这就避免了我去动手了。再啰嗦一句,喜欢我的分享的朋友记得关注我的公众号。可搜索  程序员日记,或者搜索 code2note关注,也可简单的点击文章开始的公众号名称关注。

阅读 投诉

继续阅读