三种工厂模式

工厂模式简介

工厂模式就是用工厂提供的方法代替了使用new创建对象的操作, 将创建对象统一管理和控制从而将调用者与实现类进行解耦,实现了创建者与调用者的分离。例如MyBatis中SqlSessionFactory创建SqlSession,这个就使用了工厂模式。
工厂模式的分类:

  • 简单工厂模式(静态工厂)
  • 工厂方法模式
  • 抽象工厂

简单工厂模式

有的地方也叫作静态工厂,实际上它并不算是设计模式,只不过算是工厂方法和抽象工厂的基础,不过也有一些运用的地方。比如jdk的动态代理的Proxy.newProxyInstance这个就是一个简单工厂,另外Calendar.getInstance也是一个简单的工厂。
比如你接到了生产苹果手机的订单,此时你需要建一个工厂去生产苹果手机,这里就生产iPhone X和iPhone 8 plus两款手机。

先创建一个iPhone手机的接口:

/**
 * 苹果手机
 */
public interface IPhone {

    void play();
}

创建IPhoneX系列手机

/**
 * iPhone X系列手机
 */
public class IPhoneX implements IPhone {

    @Override
    public void play() {
        System.out.println("IPhoneX");
    }
}

创建iPhone 8 plus系列手机

/**
 * iPhone 8 Plus系列手机
 */
public class IPhone8Plus implements IPhone {

    @Override
    public void play() {
        System.out.println("IPhone8Plus");
    }
}

创建生产苹果手机的工厂:

/**
 * iPhone工厂
 */
public class IPhoneFactory {

    public static IPhone produce(String model){

        if ("iPhoneX".equalsIgnoreCase(model)) {
            //生产iPhoneX
            return new IPhoneX();
        } else if ("iPhone8Plus".equalsIgnoreCase(model)) {
            //生产iPhone 8 Plus
            return new IPhone8Plus();
        }else {
            //不生产任何东西
            return null;
        }

    }

}

创建测试类:

public class Test01 {

    public static void main(String[] args) {
        //生产iPhone X手机
        IPhone iPhone = IPhoneFactory.produce("iPhoneX");
        iPhone.play();
    }
}

静态工厂优点:
通过以上代码可以看出来静态工厂的优点是封装了苹果手机创建的过程,对于使用者来说,直接调用工厂的方法就可以获取想要的手机了。

静态工厂缺点
扩展性差,倘若要想再生产iPhone 8系列手机的话,需要修改的代码比较多。

工厂方法

工厂方法模式的实质是定义一个用于创建对象的接口,然后让实现这个接口的类来决定创建哪个类的对象。
这里还是以生产iPhone X和iPhone 8 plus手机为例。
创建iphone接口:

public interface IPhone {

    void play();
}

创建iPhone 8 plus手机:

public class IPhone8Plus implements IPhone {

    @Override
    public void play() {
        System.out.println("IPhone8Plus");
    }
}

创建iPhone X手机:

public class IPhoneX implements IPhone {

    @Override
    public void play() {
        System.out.println("IPhoneX");
    }
}

创建生产手机的大工厂:

/**
 * iPhone大工厂
 */
public interface IPhoneFactory {

    IPhone produce();

}

创建生产IPhoneX的工厂:

/**
 * 生产iphonex的工厂
 */
public class IPhoneXFactory implements IPhoneFactory {

    @Override
    public IPhoneX produce() {
        return new IPhoneX();
    }
}

创建生产iPhone 8 plus的工厂:

public class IPhone8PlusFactory implements IPhoneFactory {

    @Override
    public IPhone8Plus produce() {
        return new IPhone8Plus();
    }
}

创建测试类:

public class Test02 {

    public static void main(String[] args) {
        IPhone8PlusFactory iPhone8PlusFactory = new IPhone8PlusFactory();
        IPhone8Plus iPhone8Plus = iPhone8PlusFactory.produce();
        iPhone8Plus.play();
    }
}

工厂方法模式相对于静态工厂而言在虽然代码量多了一些,但是在程序的扩展性上要更好,倘若再加入生产iPhone 8手机的工厂,是不需要修改现有的工厂的。

抽象工厂

抽象工厂模式提供了一种方式,可以将同一产品族的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。客户端程序不需要知道(或关心)它从这些内部的工厂方法中获得对象的具体类型,因为客户端程序仅使用这些对象的通用接口。抽象工厂模式将一组对象的实现细节与他们的一般使用分离开来。
产品族就是一系列相关的产品,比如生产手机,还需要生产相应的充电器,手机和充电器就相当于是两个产品族,手机可以生产苹果手机、小米手机等,充电器可以生产苹果充电器、小米充电器等。

定义充电器的接口:

/**
 * 充电器
 */
public interface Charger {

    void charge();
}

定义手机的接口:

/**
 * 手机
 */
public interface Telephone {

    void play();
}

创建苹果手机充电器的类:

/**
 * 苹果手机充电器
 */
public class AppleCharger implements Charger {

    @Override
    public void charge() {
        System.out.println("给苹果手机充电");
    }
}

创建小米手机充电器的类:

/**
 * 小米手机充电器
 */
public class XiaoMiCharger implements Charger {

    @Override
    public void charge() {
        System.out.println("给小米手机充电");
    }
}

创建iPhone X手机的类:

/**
 * IPhoneX手机
 */
public class IPhoneX implements Telephone {

    @Override
    public void play() {
        System.out.println("IPhoneX");
    }
}

创建小米8手机的类:

/**
 * XiaoMi8手机
 */
public class XiaoMi8 implements Telephone {

    @Override
    public void play() {
        System.out.println("小米8");
    }
}

创建生产手机的大工厂:

/**
 * 生产手机的大工厂
 *
 * 要生产手机和相应的充电器
 */
public interface PhoneFactory {

    Charger produceCharger();

    Telephone producePhone();
}

创建生产iPhone X手机的工厂:

/**
 * 生产苹果手机的工厂
 */
public class IPhoneXFactory implements PhoneFactory {

    @Override
    public Charger produceCharger() {
        return new AppleCharger();
    }

    @Override
    public Telephone producePhone() {
        return new IPhoneX();
    }
}

创建生产小米8手机的工厂:

public class XiaoMi8Factory implements PhoneFactory {

    @Override
    public Charger produceCharger() {
        return new XiaoMiCharger();
    }

    @Override
    public Telephone producePhone() {
        return new XiaoMi8();
    }
}

创建测试类:

public class Test03 {

    public static void main(String[] args) {
        IPhoneXFactory iPhoneXFactory = new IPhoneXFactory();
        Charger charger = iPhoneXFactory.produceCharger();
        Telephone iPhoneX = iPhoneXFactory.producePhone();
        charger.charge();
        iPhoneX.play();
    }
}

工厂方法和抽象工厂的区别在于工厂方法的一个工厂只能创建一个具体产品。而抽象工厂的一个工厂可以创建属于一类类型的多种具体产品。

三种方式的总结

静态工厂 : 用来生产同一等级结构中的任意产品。产品的创建是由你传入参数决定的。

工厂方法 :用来生产同一等级结构中的固定产品。一个工厂只能生产一个固定的产品。

抽象工厂 :用来生产不同产品族的全部产品。一个工厂可以生产跟该产品相关的一系列产品。