设计模式 | 简单工厂、工厂方法和抽象工厂

112 阅读4分钟

简单工厂

在介绍工厂方法和抽象工厂前,我们要先简单介绍一下简单工厂

老麻花准备在大学城开一家奶茶店,名字就叫麻花茶馆吧。因为一开始只有一家店,麻花可能采用简单工厂的模式进行开发:

先定义奶茶的接口:

public interface Tea {
    void prepare();
    void boil();
    void pack();
}

建一个简单工厂,制造两款奶茶试试水:

class TeaA implements Tea {

    @Override
    public void prepare() {
        System.out.println("prepare tea A");
    }

    @Override
    public void boil() {
        System.out.println("boil tea A");
    }

    @Override
    public void pack() {
        System.out.println("pack tea A");
    }
}

class TeaB implements Tea {
    @Override
    public void prepare() {
        System.out.println("prepare tea B");
    }

    @Override
    public void boil() {
        System.out.println("boil tea B");
    }

    @Override
    public void pack() {
        System.out.println("pack tea B");
    }
}

public class SimpleTeaFactory {

    public static Tea createTea(String type) {
        Tea tea = null;
        if (type.equals("A")) {
            tea = new TeaA();
        } else if (type.equals("B")) {
            tea = new TeaB();
        }
        if (tea != null) {
            tea.prepare();
            tea.boil();
            tea.pack();
        }
        return tea;
    }

}

最后把奶茶店开到大学城:

public class TeaStore {

    SimpleTeaFactory simpleTeaFactory;

    public TeaStore(SimpleTeaFactory simpleTeaFactory) {
        this.simpleTeaFactory = simpleTeaFactory;
    }

    public Tea orderTea(String type) {
        return SimpleTeaFactory.createTea(type);
    }

    public static void main(String[] args) {
        TeaStore teaStore = new TeaStore(new SimpleTeaFactory());
        teaStore.orderTea("A");
        teaStore.orderTea("B");
    }

}

简单工厂存在的问题

虽然我们已经将产品、工厂、门店进行了分离。但如果我要开发一款新的品类(坤不离手),就需要在工厂类中新增if-else逻辑判断else if (type.equals("坤不离手"))

工厂方法

为了解决上面的问题,我们对工厂进行升级,创建一个抽象工厂类,定义创建奶茶的接口。对于每一个奶茶品类,我们都要实例化一个工厂类来制作该奶茶,这样我们就移除了简单工厂中的if-else逻辑判断

public interface AbstractTeaFactory {

    public Tea createTea();

}

class TeaA implements Tea {

    @Override
    public void prepare() {
        System.out.println("prepare TeaA");
    }

    @Override
    public void boil() {
        System.out.println("boil TeaA");
    }

    @Override
    public void pack() {
        System.out.println("pack TeaA");
    }
}

class FactoryA implements AbstractTeaFactory {
    @Override
    public Tea createTea() {
        Tea tea = new TeaA();
        tea.prepare();
        tea.boil();
        tea.pack();

        return tea;
    }
}

class TeaB implements Tea {
    @Override
    public void prepare() {
        System.out.println("prepare TeaB");
    }

    @Override
    public void boil() {
        System.out.println("boil TeaB");
    }

    @Override
    public void pack() {
        System.out.println("pack TeaB");
    }
}

class FactoryB implements AbstractTeaFactory {
    @Override
    public Tea createTea() {
        Tea tea = new TeaB();
        tea.prepare();
        tea.boil();
        tea.pack();
        return tea;
    }
}

当我们需要添加一个新品类时,只需要实例化一个新的工厂类,实现新品类的制作。 接下来,我们升级后的奶茶店就可以开业了:

public class TeaStore {

    public static void main(String[] args) {
        Tea teaA = new FactoryA().createTea();
        Tea teaB = new FactoryB().createTea();
    }

}

工厂方法的缺点

虽然工厂方法通过实例化工厂类,实现createTea方法,生成具体的产品,避免了简单工厂中的if-else判断。但随着业务的增加,系统中的类可能会成倍增加,增加代码的复杂性。

抽象工厂

随着麻花茶馆的生意越做越好,我们决定出海!出海的第一站就是印度。但印度老哥干净又卫生,总有些特殊需求。如果把针对印度老哥的工厂都开在国内,工厂太多了,公司不好管理。因此,我们决定,把针对印度老哥的工厂与国内的工厂区分开来,打包运往印度。

我们先想好印度和国内都会生产的品类:

public interface BubbleTea {

    void prepare();
    void boil();
    void pack();

}


public interface FruitTea {

    void prepare();
    void pack();

}

修改抽象工厂,国内工厂和印度工厂都是从同一个模子里造出来的

public interface AbstractTeaFactory {

    public BubbleTea createBubbleTea();

    public FruitTea createFruitTea();

}

国内的工厂有自己的特色:

class PutianBubbleTea implements BubbleTea{

    @Override
    public void prepare() {
        System.out.println("Prepare PutianBubbleTea");
    }

    @Override
    public void boil() {
        System.out.println("Boiling PutianBubbleTea");
    }

    @Override
    public void pack() {
        System.out.println("Pack PutianBubbleTea");
    }
}

class PutianFruitTea implements FruitTea {
    @Override
    public void prepare() {
        System.out.println("Prepare PutianFruitTea");
    }

    @Override
    public void pack() {
        System.out.println("Pack PutianFruitTea");
    }
}

public class PutianTeaFactory implements AbstractTeaFactory{

    @Override
    public BubbleTea createBubbleTea() {
        BubbleTea bubbleTea = new PutianBubbleTea();
        bubbleTea.prepare();
        bubbleTea.boil();
        bubbleTea.pack();
        return bubbleTea;
    }

    @Override
    public FruitTea createFruitTea() {
        FruitTea fruitTea = new PutianFruitTea();
        fruitTea.prepare();
        fruitTea.pack();
        return fruitTea;
    }
}

印度老哥的工厂也有自己的特色:

class IndiaBubbleTea implements BubbleTea {

    @Override
    public void prepare() {
        System.out.println("Preparing India Bubble Tea");
        System.out.println("干净又卫生");
    }

    @Override
    public void boil() {
        System.out.println("Boiling India Bubble Tea");
        System.out.println("干净又卫生");
    }

    @Override
    public void pack() {
        System.out.println("Packing India Bubble Tea");
        System.out.println("干净又卫生");
    }
}

class IndiaFruitTea implements FruitTea {
    @Override
    public void prepare() {
        System.out.println("Preparing India Fruit Tea");
        System.out.println("干净又卫生");
    }

    @Override
    public void pack() {
        System.out.println("Packing India Fruit Tea");
        System.out.println("干净又卫生");
    }
}

public class IndiaTeaFactory implements AbstractTeaFactory {
    @Override
    public BubbleTea createBubbleTea() {
        BubbleTea bubbleTea = new IndiaBubbleTea();
        bubbleTea.prepare();
        bubbleTea.boil();
        bubbleTea.pack();
        return bubbleTea;
    }

    @Override
    public FruitTea createFruitTea() {
        FruitTea fruitTea = new IndiaFruitTea();
        fruitTea.prepare();
        fruitTea.pack();
        return fruitTea;
    }
}

最后,开业大吉!

public class TeaStore {

    public static void main(String[] args) {
        new PutianTeaFactory().createBubbleTea();
        new PutianTeaFactory().createFruitTea();

        System.out.println("============================");

        new IndiaTeaFactory().createBubbleTea();
        new IndiaTeaFactory().createFruitTea();
    }

}

总结

  • 简单工厂:适用业务简单,产品比较固定,不会经常改变的工厂类
  • 工厂方法:实例化工厂类,通过实现createTea方法,生成具体的产品。可扩展性强于简单工厂,但随着业务的增加,系统中的类可能会成倍增加,使代码变得复杂。
  • 抽象工厂:针对工厂方法类成倍增加的问题,通过分组的方式减少工厂类的数量。但凡事都有代价,抽象工厂通过分组减少了工厂类的数量,但在分组中扩展产品就会变得比较困难。