一、工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。

 工厂模式在《Java与模式》中分为三类:

1)简单工厂模式(Simple Factory):不利于产生系列产品;

2)工厂方法模式(Factory Method):又称为多形性工厂;

3)抽象工厂模式(Abstract Factory):又称为工具箱,产生产品族,但不利于产生新的产品;
             这三种模式从上到下逐步抽象,并且更具一般性。
             GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。

二、简单工厂模式

1.简单工厂模式又称静态工厂方法模式。重命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。

在简单工厂模式中,一个工厂类处于对产品类实例化调用的中心位置上,它决定那一个产品类应当被实例化, 如同一个交通警察站在来往的车辆流中,决定放行那一个方向的车辆向那一个方向流动一样。
        先来看看它的组成:

         1) 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑。在java中它往往由一个具体类实现。

         2) 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。

         3) 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。

 
         4) 客户端:调用工厂类产生实例,并调用实例的方法进行相应工作。
简单工厂模式的UML图:
 
2. 代码案例1演示:
(1)定义一个抽象产品角色,新建立一个食物的接口:
  1. package com.diermeng.designPattern.SimpleFactory;
  2. /*
  3. * 产品的抽象接口
  4. */
  5. public interface Food {
  6. /*
  7. * 获得相应的食物
  8. */
  9. public void get();
  10. }

(2)接下来建立具体的产品:麦香鸡和薯条

根据上面接口,定义产品麦香鸡:

  1. package com.diermeng.designPattern.SimpleFactory.impl;
  2. import com.diermeng.designPattern.SimpleFactory.Food;
  3. /*
  4. * 麦香鸡对抽象产品接口的实现
  5. */
  6. public class McChicken implements Food{
  7. /*
  8. * 获取一份麦香鸡
  9. */
  10. public void get(){
  11. System.out.println("我要一份麦香鸡");
  12. }
  13. }

根据上面接口,定义产品薯条

  1. package com.diermeng.designPattern.SimpleFactory.impl;
  2. import com.diermeng.designPattern.SimpleFactory.Food;
  3. /*
  4. * 薯条对抽象产品接口的实现
  5. */
  6. public class Chips implements Food{
  7. /*
  8. * 获取一份薯条
  9. */
  10. public void get(){
  11. System.out.println("我要一份薯条");
  12. }
  13. }

(3)现在建立一个食物加工工厂:

  1. package com.diermeng.designPattern.SimpleFactory.impl;
  2. import com.diermeng.designPattern.SimpleFactory.Food;
  3. public class FoodFactory {
  4. private FoodFactory() { }
  5. public static Food getFood(String type) throws Exception {
  6. if(type.equalsIgnoreCase("mcchicken")) {
  7. return McChicken.class.newInstance();
  8. } else if(type.equalsIgnoreCase("chips")) {
  9. return Chips.class.newInstance();
  10. } else {
  11. System.out.println("哎呀!找不到相应的实例化类啦!");
  12. return null;
  13. }
  14. }
  15. }

(4)最后我们建立测试客户端:

  1. package com.diermeng.designPattern.SimpleFactory.client;
  2. import com.diermeng.designPattern.SimpleFactory.Food;
  3. import com.diermeng.designPattern.SimpleFactory.impl.FoodFactory;
  4. /*
  5. * 测试客户端
  6. */
  7. public class SimpleFactoryTest {
  8. public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
  9. //实例化各种食物
  10. Food mcChicken = FoodFactory.getFood("McChicken");
  11. Food chips = FoodFactory.getFood("Chips");
  12. Food eggs = FoodFactory.getFood("Eggs");
  13. //获取食物
  14. if(mcChicken!=null){
  15. mcChicken.get();
  16. }
  17. if(chips!=null){
  18. chips.get();
  19. }
  20. if(eggs!=null){
  21. eggs.get();
  22. }
  23. }
  24. }

测试结果如下:

哎呀!找不到相应的实例化类啦!

我要一份麦香鸡

我要一份薯条

3. 代码案例2演示:

(1)定义一个抽象产品角色,动物类:

  1. package cn.itcast_01;
  2. //抽象类
  3. public abstract class Animal {
  4. public abstract void eat();
  5. }

(2)接下来是具体产品角色,如下:

  1. package cn.itcast_01;
  2. //具体产品角色Cat
  3. public class Cat extends Animal {
  4. @Override
  5. public void eat() {
  6. System.out.println("猫吃鱼");
  7. }
  8. }
  1. package cn.itcast_01;
  2. //具体产品角色Dog
  3. public class Dog extends Animal {
  4. @Override
  5. public void eat() {
  6. System.out.println("狗吃肉");
  7. }
  8. }

(3)创建一个动物工厂类,如下:

  1. package cn.itcast_01;
  2. //工厂类角色
  3. public class AnimalFactory {
  4. private AnimalFactory() {
  5. }
  6. // public static Dog createDog() {
  7. // return new Dog();
  8. // }
  9. //
  10. // public static Cat createCat() {
  11. // return new Cat();
  12. // }
  13. public static Animal createAnimal(String type) {
  14. if ("dog".equals(type)) {
  15. return new Dog();
  16. } else if ("cat".equals(type)) {
  17. return new Cat();
  18. } else {
  19. return null;
  20. }
  21. }
  22. }

(4)客户端测试类,如下:

  1. package cn.itcast_01;
  2. //测试类
  3. public class AnimalDemo {
  4. public static void main(String[] args) {
  5. // 具体类调用
  6. Dog d = new Dog();
  7. d.eat();
  8. Cat c = new Cat();
  9. c.eat();
  10. System.out.println("------------");
  11. // 工厂有了后,通过工厂给造
  12. // Dog dd = AnimalFactory.createDog();
  13. // Cat cc = AnimalFactory.createCat();
  14. // dd.eat();
  15. // cc.eat();
  16. // System.out.println("------------");
  17. // 工厂改进后
  18. Animal a = AnimalFactory.createAnimal("dog");
  19. a.eat();
  20. a = AnimalFactory.createAnimal("cat");
  21. a.eat();
  22. // NullPointerException
  23. a = AnimalFactory.createAnimal("pig");
  24. if (a != null) {
  25. a.eat();
  26. } else {
  27. System.out.println("对不起,暂时不提供这种动物");
  28. }
  29. }
  30. }

4. 小结:

  简单工厂模式优点:客户端不需要在负责对象的创建,从而明确各个类的职责。

      简单工厂模式缺点:这个静态工厂类负责所有对象的创建,如果有新的对象添加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期维护。

三、工厂方法模式

1. 工厂方法模式是简单工厂模式的进一步抽象化和推广,工厂方法模式里不再只由一个工厂类决定那一个产品类应当被实例化,这个决定被交给抽象工厂的子类去做。

   上面我们提到了简单工厂模式缺点是:这个静态工厂类负责所有对象的创建,如果有新的对象添加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期维护。因此,为了弥补简单工厂模式缺点,就出现了工厂方法模式。


  来看下它的组成:

1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。

2具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。

3抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。

4具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
       工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力;而且这样使得结构变得灵活 起来——当有新的产品(即暴发户的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代 码。可以看出工厂角色的结构也是符合开闭原则的!

2. 工厂方法模式代码案例1:

  1. //抽象产品角色
  2. public interface Moveable {
  3. void run();
  4. }
  5. //具体产品角色
  6. public class Plane implements Moveable {
  7. @Override
  8. public void run() {
  9. System.out.println("plane....");
  10. }
  11. }
  12. //具体产品角色
  13. public class Broom implements Moveable {
  14. @Override
  15. public void run() {
  16. System.out.println("broom.....");
  17. }
  18. }
  19. //抽象工厂
  20. public abstract class VehicleFactory {
  21. abstract Moveable create();
  22. }
  23. //具体工厂---针对具体产品Plane
  24. public class PlaneFactory extends VehicleFactory{
  25. public Moveable create() {
  26. return new Plane();
  27. }
  28. }
    30 //具体工厂---针对具体产品Broom
  29. public class BroomFactory extends VehicleFactory{
  30. public Moveable create() {
  31. return new Broom();
  32. }
  33. }
  34. //测试类
  35. public class Test {
  36. public static void main(String[] args) {
  37. VehicleFactory factory = new BroomFactory();
  38. Moveable m = factory.create();
  39. m.run();
  40. }
  41. }

3.  工厂方法模式代码案例2:

代码实现:

(1)抽象产品角色

  1. package cn.itcast_02;
  2. //抽象动物类
  3. public abstract class Animal {
  4. public abstract void eat();
  5. }

(2)具体产品角色Dog

  1. package cn.itcast_02;
  2. //具体产品角色Dog
  3. public class Dog extends Animal {
  4. @Override
  5. public void eat() {
  6. System.out.println("狗吃肉");
  7. }
  8. }

(3)具体产品角色Cat

  1. package cn.itcast_02;
  2. //具体产品角色Cat
  3. public class Cat extends Animal {
  4. @Override
  5. public void eat() {
  6. System.out.println("猫吃鱼");
  7. }
  8. }

(4)抽象工厂

  1. package cn.itcast_02;
  2. //抽象工厂
  3. public interface Factory {
  4. public abstract Animal createAnimal();
  5. }

(5)具体工厂--Dog

  1. package cn.itcast_02;
  2. //具体工厂--Dog
  3. public class DogFactory implements Factory {
  4. @Override
  5. public Animal createAnimal() {
  6. return new Dog();
  7. }
  8. }

(6)具体工厂--Cat

  1. package cn.itcast_02;
  2. //具体工厂--Cat
  3. public class CatFactory implements Factory {
  4. @Override
  5. public Animal createAnimal() {
  6. return new Cat();
  7. }
  8. }

(7)AnimalDemo测试类:

  1. package cn.itcast_02;
  2. //测试类
  3. public class AnimalDemo {
  4. public static void main(String[] args) {
  5. // 需求:我要买只狗
  6. Factory f = new DogFactory();
  7. Animal a = f.createAnimal();
  8. a.eat();
  9. System.out.println("-------");
  10. //需求:我要买只猫
  11. f = new CatFactory();
  12. a = f.createAnimal();
  13. a.eat();
  14. }
  15. }

测试结果,如下:

4. 小结:

  工厂方法模式优点:客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象的增加,只需要增加一个具体的类和具体的工厂类即可,不需要影响已有的代码,后期维护容易,增强系统的扩展性。

  工厂方法模式缺点:需要额外的编写代码,增加工作量。

四、抽象工厂模式:

1. 抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。

      在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。我们依然拿生产汽车的例子来说明他们之间的区别。

抽象工厂模式UML图:

在上面的类图中,两厢车和三厢车称为两个不同的等级结构;而2.0排量车和2.4排量车则称为两个不同的产品族。再具体一点,2.0排量两厢车和2.4排量两厢车属于同一个等级结构,2.0排量三厢车和2.4排量三厢车属于另一个等级结构;而2.0排量两厢车和2.0排量三厢车属于同一个产品族,2.4排量两厢车和2.4排量三厢车属于另一个产品族。

      明白了等级结构和产品族的概念,就理解工厂方法模式和抽象工厂模式的区别了,如果工厂的产品全部属于同一个等级结构,则属于工厂方法模式;如果工厂的产品来自多个等级结构,则属于抽象工厂模式。在本例中,如果一个工厂模式提供2.0排量两厢车和2.4排量两厢车,那么他属于工厂方法模式;如果一个工厂模式是提供2.4排量两厢车和2.4排量三厢车两个产品,那么这个工厂模式就是抽象工厂模式,因为他提供的产品是分属两个不同的等级结构。当然,如果一个工厂提供全部四种车型的产品,因为产品分属两个等级结构,他当然也属于抽象工厂模式了。

2. 抽象工厂模式代码:

  1. interface IProduct1 {
  2. public void show();
  3. }
  4. interface IProduct2 {
  5. public void show();
  6. }
  7. class Product1 implements IProduct1 {
  8. public void show() {
  9. System.out.println("这是1型产品");
  10. }
  11. }
  12. class Product2 implements IProduct2 {
  13. public void show() {
  14. System.out.println("这是2型产品");
  15. }
  16. }
  17. interface IFactory {
  18. public IProduct1 createProduct1();
  19. public IProduct2 createProduct2();
  20. }
  21. class Factory implements IFactory{
  22. public IProduct1 createProduct1() {
  23. return new Product1();
  24. }
  25. public IProduct2 createProduct2() {
  26. return new Product2();
  27. }
  28. }
  29. public class Client {
  30. public static void main(String[] args){
  31. IFactory factory = new Factory();
  32. factory.createProduct1().show();
  33. factory.createProduct2().show();
  34. }
  35. }

抽象工厂模式的优点:

        抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理。

 

抽象工厂模式的缺点:

       产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的。

 

适用场景:

       当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点。

 

总结:

       无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。

       所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。

Java设计模式02:常用设计模式之工厂模式(创建型模式)的更多相关文章

  1. 设计模式02: Abstract Factory 抽象工厂(创建型模式)

    Abstract Factory 抽象工厂(创建型模式) 常见的对象创建方法:    //创建一个Road对象    Road road=new Road();    new的问题:    -实现依赖 ...

  2. FactoryMethod工厂方法模式(创建型模式)

    1.工厂方法模式解决的问题 现在有一个抽象的游戏设施建造系统,负责构建一个现代风格和古典风格的房屋和道路. 前提:抽象变化较慢,实现变化较快(不稳定) 整个抽象的游戏设施建造系统相对变化较慢,本例中只 ...

  3. Prototype原型模式(创建型模式)

    1.原型模式解决的问题 现在有一个抽象的游戏设施建造系统,负责构建一个现代风格和古典风格的房屋和道路. 前提:抽象变化较慢,实现变化较快(不稳定) 整个抽象的游戏设施建造系统相对变化较慢,本例中只有一 ...

  4. Java 23种设计模式详尽分析与实例解析之一--创建型模式

    面向对象的设计原则 常用的面向对象设计原则包括7个,这些原则并不是独立存在的,它们相互依赖.互为补充. Java设计模式 创建型模式 简单工厂模式 模式动机: 考虑一个简单的软件应用场景,一个软件系统 ...

  5. 工厂方法模式——创建型模式02

    1. 简单工厂模式     在介绍工厂方法模式之前,先介绍一下简单工厂模式.虽然简单工厂模式不属于GoF 23种设计模式,但通常将它作为学习其他工厂模式的入门,并且在实际开发中使用的也较为频繁. (1 ...

  6. 设计模式之美:Creational Patterns(创建型模式)

    创建型模式(Creational Patterns)抽象了对象实例化过程. 它们帮助一个系统独立于如何创建.组合和表示它的那些对象. 一个类创建型模式使用继承改变被实例化的类. 一个对象创建型模式将实 ...

  7. 设计模式(五):PROTOTYPE原型模式 -- 创建型模式

    1.定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 2.适用场景 原型模式的主要思想是基于现有的对象克隆一个新的对象出来,一般是有对象的内部提供克隆的方法,通过该方法返回一个对 ...

  8. 设计模式(二): BUILDER生成器模式 -- 创建型模式

    1.定义 将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式. 2.适用场景 1. 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式 ...

  9. 设计模式(三): FACTORY工厂模式 -- 创建型模式

    1.定义 定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类. 2.适用场景 1.第一种情况是对于某个产品,调用者清楚地知道应该使用哪个具体 ...

  10. 设计模式(四):SIMPLE FACTORY简单工厂模式 -- 创建型模式

    1.定义 简单工厂模式又称静态工厂方法模式.重命名上就可以看出这个模式一定很简单.它存在的目的很简单:定义一个用于创建对象的接口. 2.适用场景 如果一个客户要一款宝马车,一般的做法是客户去创建一款宝 ...

随机推荐

  1. Java操作Oracle数据库以及调用存储过程

    操作Oracle数据库 publicclass DBConnection {     //jdbc:oracle:thin:@localhost:1521:orcl     publicstaticf ...

  2. C#匿名类型(Anonymous Type)学习日记

    当我们不要定义复杂的方法,事件,构造函数这样复杂的类的时候,可以动态的生成一个自定义的数据类型 --> 匿名类型. 1.定义匿名类型 定义一个匿名类型时,需要用到 var 关键字和对象初始化语法 ...

  3. 聊聊js运算符 ‘与(&&)’和‘ 或(||)’

    一,先来几个问题,看给位能都全部答对. var objA1 = {x:1}; var objA2 = {x:2}; var resultA = objA1 && objA2; //请问 ...

  4. NEURAL NETWORKS, PART 2: THE NEURON

    NEURAL NETWORKS, PART 2: THE NEURON A neuron is a very basic classifier. It takes a number of input ...

  5. 【itext】7步制作兼容各种文档格式的Itext5页眉页脚 实现page x pf y

    itext5页眉页脚工具类,实现page x of y 完美兼容各种格式大小文档A4/B5/B3,兼容各种文档格式自动计算页脚XY轴坐标 鉴于没人做的这么细致,自己就写了一个itext5页眉页脚工具类 ...

  6. GemFire

    一.GemFire是什么?   如果你了解Redis或memCached,那么恭喜,你很快就能理解GemFire是什么,没错,你可以把它理解为一个增强版的Redis,具体在哪些方面增强,我们日后慢慢聊 ...

  7. Katu Puzzle

    poj3678:http://poj.org/problem?id=3678 题意:给你一些数,然后这些要么是0要么是1,然后回给出一些数之间的and,or,xor的值,问你是否存在一组解. 题解:2 ...

  8. 解除網頁無法選取文字、鎖右鍵限制:Enable Copy(Chrome 擴充套件)

    有些网页因会因为某些因素而禁止浏览者直接复制网页上的内容,虽然我们了解站方的意思,不过有些时候会造成一些不必要的困扰. Enable Copy 这款Chrome 扩充套件可以帮你一键解除封锁右键和选取 ...

  9. SQL*Net more data from client

    SQL*Net more data from client The server is waiting on the client to send more data to its client sh ...

  10. Spark RDD Persistence

    Spark最为重要的特性之一就是可以在多个操作(Action)之间,将一个或多个RDD关联的数据集(Dataset)以分区(Partition)为单位进行持久化(Persist)或缓存(Cache), ...