一篇文章搞定Java工厂模式

版权声明:欢迎转载,转载请注明出处 https://blog.csdn.net/u012810020/article/details/55253417

简述:

    工厂模式属于创建型模式,它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。简单的说,工厂模式能够帮助我们轻松方便地构造对象实例,而不必关心构造对象实例的细节和复杂过程。
分类:
    工厂模式可以分为简单工厂、工厂方法和抽象工厂。这篇博文一一介绍一下。

简单工厂:

    简单工厂模式(Simple Factory Pattern)属于类的创新型模式,又叫静态工厂方法模式(Static FactoryMethod Pattern),是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类(或者父接口)。
    举个例子,以手机为例,目前流行的有三星与苹果手机,手机的基本功能就是拨打电话,那么首先对手机进行抽象,然后三星手机与苹果手机是具体的手机实现类。然后创建一个手机工厂去生产手机。OK,接下来以这个为例实现简单工厂模式。

UML图:


实例:

    首先创建接口Mobile:使用接口暴露公共的方法,使用类来提供公共的实现

public interface Mobile {
     String call();
}
    具体产品实现类如下:

public class AppleMobile implements Mobile {

    private String call;

    public AppleMobile() {
        call = "苹果手机拨打电话";
        System.out.println("Apple手机生产完毕!");
    }

    @Override
    public String call() {
        return call != null ? call : null;
    }

}
public class SamsungMobile implements Mobile {
     private String call;

     public SamsungMobile() {
          call = "三星手机拨打电话";
          System.out.println("Samsung手机生产完毕!");
     }

     @Override
     public String call() {
          return call != null ? call : null;
     }
}

    这些功能类似的类的实例化成为了一个问题,每次 new 对象很麻烦,封装成简单工厂模式。

public class MobileFactory {
    public static final int APPLE = 1;
    public static final int SAMSUNG = 2;

    public static Mobile getMobile(int type) {
        if (APPLE == type) {
            return new AppleMobile();
        } else if (SAMSUNG == type) {
            return new SamsungMobile();
        }else {
            throw new IllegalArgumentException();
        }
    }
}
简单工厂模式所涉及的这个角色我们已经创建完成,接下来我们使用客户端测试一下:

public class Client {

    public static void main(String[] args) {
        AppleMobile mobile = (AppleMobile)MobileFactory.getMobile(MobileFactory.APPLE);
        SamsungMobile samsungMobile = (SamsungMobile) MobileFactory.getMobile(MobileFactory.SAMSUNG);
    }

}
  
    经过上述的案例我们已经基本掌握了简单工厂模式,那现在思考一个问题,假如现在业务增加,需要生产华为手机,我们就要再创建一个再创建一个HuaweiMobile类,接下来再修改MobileFactory类,或者我们要对AppleMobile以及SamsungMobile做些业务上的变更,那么我们还要去修改AppleMobile或者SamsungMobile。如果说项目的业务非常简单我们做一些简单的修改也无妨,但是如果项目已经成熟且有些复杂,这时候再做修改就不那么简单了。所以这个问题也暴露出简单工厂模式的一个弊端:简单工厂模式不利于拓展,违背了“开闭原则 ”,每次添加一个类,都要去修改工厂类。所以此时“工厂方法模式”利剑出鞘。

工厂方法模式

    工厂方法模式其原理就是对简单工厂模式也进行抽象。更具体的说就是对简单工厂模式中的工厂类与产品类再进一步封装。还以上述的例子为例继续工厂方法模式。

    工厂方法模式UML:



实例解析:

   我们基于简单工厂的上述案例继续封装。我们知道工厂方法模式只是对简单工厂模式中工厂类的进一步抽象。接下来我们首先给出MobileFactory 的封装接口。
public interface MobileFactory {
     public Mobile getMobile();
}
    然后我们再看一下AppleFactory 和SamsungFactory 类:
public class AppleFactory implements MobileFactory{

     @Override
     public Mobile getMobile() {
          return new AppleMobile();
     }

}


public class SamsungFactory implements MobileFactory{

     @Override
     public Mobile getMobile() {
          return new SamsungMobile();
     }
}

    OK,到此一个基本的工厂方法模式也已经创建完毕,刚才已经说了工厂方法模式是为了解决简单工厂模式不符合“开闭原则”而产生的。那么现在我们添加一个生产华为手机的业务,UML图如下:
            

    OK,从UML图看出再增加Huawei手机业务不需要修改代码了,这样完美解决了简单工厂不能实现“开闭原则”的弊端。我们再思考一个问题,如果此时我们还需要手机充分电器,每种手机都需要自己的手机充电器,此时我们需要怎么做呢?如果继续采用工厂方法模式那么则需要再创建手机充电器工厂,那么这样的话每种产品需要创建一个工厂类,两种手机需要创建两个手机充电器工厂类,这样一来代码变得非常的冗余。我们再仔细想一下,每种手机和手机手机充电器存在着相互依赖的关系,我们有必要再去创建一个相应的工厂类吗?确实是这样,这就是抽象工厂模式。简单来说,可以把有一些有联系或者相近的产品,放到一个工厂去生产,没有必要单独再开一个工厂了。 现在就让我们认识一下抽象工厂模式吧!

抽象工厂模式

    抽象工厂模式是工厂方法模式的升级版本,设计模式中抽象工厂原文:"Provide an interface for creating families of related or dependent objects without specifying their concrete classes",意思是“为创建一组相关或相互依赖的对象提供一个接口,无需指定它们的具体类”。在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。
    举个例子,我们购买手机时都会包含两样基本的东西:手机和手机充电器。那么我们将手机视作一种产品Mobile,将手机充电器Charger视作另一种产品,我们都知道它们二者具有相互依赖的关系,我们将其视作一个产品族。目前流行的手机有苹果和三星(虽然受Note7爆砸门的影响,但三星手机依然是手机界的老大哥),那么可以看做是两个产品族。然后我们再抽象出工厂类MobileFactory,该工厂类用于生产一个产品族(也即是生产手机和手机充电器),最后再根据Apple手机和Samsung手机分别创建两个具体工厂类AppleFactory和SamsungFactory用于生产Apple手机和Apple充电器以及Samsung手机和Samsung手机充电器。OK,接下来我们就以这样一个背景为例实现一个简单的抽象工厂案例。

    UML图:

           

代码实现:

    根据上述问题和UML图,首先抽象出第一个产品Mobile如下:
/**
 * 类描述:产品类Mobile
 *
 * @author lzy
 *
 */
public interface Mobile {
     String getName();
}

   然后具体产品类AppleMobile和SamsungMobile如下:

public class AppleMobile implements Mobile {
     private String name;

     public AppleMobile() {
          name = "苹果手机";
          System.out.println("Apple手机生产完毕!");      
     }

     @Override
     public String getName() {
          return name != null ? name : null;
     }
}

public class SamsungMobile implements Mobile {
     private String name;

     public SamsungMobile() {
          name = "三星手机";
          System.out.println("Samsung手机生产完毕!");
     }

     @Override
     public String getName() {
          return name != null ? name : null;
     }

}

    另一种产品手机手机充电器Charger和具体产品类AppleCharger以及SamsungCharger与Mobile类似,为了方面理解直接把代码贴出来:

/**
 * 产品类:Charger
 *
 * @author lzy
 *
 */
public interface Charger {
    String getName();
}

    两个具体的charger:

public class AppleCharger implements Charger {
     private String name;

     public AppleCharger() {
          name = "苹果手机充电器";
          System.out.println("Apple手机充电器生产完毕!");
     }

     @Override
     public String getName() {
          return name != null ? name : null;
     }
}

public class SamsungCharger implements Charger {
     private String name;

     public SamsungCharger() {
          name = "三星充电器";
          System.out.println("Samsung手机充电器生产完毕!");
     }

     @Override
     public String getName() {
          return name != null ? name : null; 
     }
}

    OK,到此为止,两个产品族(每个产品族两种产品)构建完毕,接下来就来创建产品族对应的工厂。
    要创建工厂我们需要就工厂进行抽象,那么具体该怎么抽象呢?那么让我们回到抽象工厂的描述:创建一组相关或相互依赖的对象。根据描述我们可以知道工厂就是用来创建一组相关产品的对象(也就是一个产品族的相对应的对象)。OK,考虑到每个产品族工厂要生产两种产品,所以对工厂进行如下抽象:
public interface MobileFactory {
     // 生产手机
     Mobile getMobile();

     // 生产充电器
     Charger getCharger();
}

    接下来就要创建具体工厂,AppleFactory生产苹果手机产品族对象,SamsungFactory生产三星手机产品族对象,具体代码实现如下:

public class AppleFactory implements MobileFactory {
     // 生产苹果手机
     @Override
     public Mobile getMobile() {
          return new AppleMobile();
     }

     // 生产苹果手机充电器
     @Override
     public Charger getCharger() {
          return new AppleCharger();
     }
}

public class SamsungFactory implements MobileFactory {
     // 生产三星手机
     @Override
     public Mobile getMobile() {
          return new SamsungMobile();
     }

     // 生产三星手机充电器
     @Override
     public Charger getCharger() {
          return new SamsungCharger();
     }
}

   目前为止,我们的抽象工厂和具体工厂创建完毕,接下来写一个客户端调用一下:

public class Client {

     public static void main(String[] args) {
          AppleFactory appleFactory = new AppleFactory();
          AppleMobile appleMobile = (AppleMobile) appleFactory.getMobile();
          AppleCharger appleCharger = (AppleCharger) appleFactory.getCharger();

          SamsungFactory samsungFactory = new SamsungFactory();
          SamsungMobile samsungMobile = (SamsungMobile) samsungFactory.getMobile();
          SamsungCharger samsungCharger = (SamsungCharger) samsungFactory.getCharger();
     }
}

    目前为止一个抽象工厂的案例全部完成,那么我们现在可以思考几个问题:①抽象工厂与工厂方法模式有什么区别 ②抽象工厂的优势在哪里?
    抽象工厂与工厂方法模式的区别:
    通过前面的案例我们可以看出他们的抽象工厂生产的产品不同,工厂方法模式中工厂生产的产品比较单一,换句话说工厂方法模式中生产的产品可能就是一个产品族(相对于抽象工厂来说)的一个产品,换成术语说就是生产的产品就是所谓的结构性产品。而抽象工厂生产的产品是一个产品族。
    抽象工厂的优势在哪里?
    我们在抽象工厂模式的开头就说:抽象工厂模式是工厂方法模式的升级版本。因此抽象工厂模式一样遵循“开闭原则”,同时抽象工厂中每个具体工厂类可以创建多个具体产品类的实例,所以相比工厂方法模式减少了产品工厂的创建。


    结尾啦, 给自己也给大家一些工厂模式优化的Tips:
    ① 苹果手机有iPhone6、iPhone7,三星手机有Note系列、Galaxy系列等,如果考虑这些复杂因素产品类应该做进一步抽象。
    ② 客户端调用的时候针对不同产品要做拆箱与装箱操作,这样一来使用不方便同时装箱与拆箱也比较耗时,所以在做产品抽象的时候可以添加泛型。


猜你喜欢

转载自blog.csdn.net/u012810020/article/details/55253417