设计模式之工厂模式

图1

工厂模式是23种设计模式中比较基础的设计模式,属于创建型的设计模式。主要分为简单工厂设计模式,工厂方法和抽象工厂设计模式三类。

简单工厂模式

简单工厂模式又称为静态工厂方法模式,主要用于创建同一类产品的设计模式,何为同一类产品?也就是实现了同一接口的具体产品都属于同一类产品。一般只有一个工厂类,该工厂类提供一个静态创建产品的方法,根据约定的类型或者直接根据具体产品的类名来生产相应的产品实例。使用者只需要告诉工厂类创建什么样的产品就行,而不需要关注具体的产品实现,具体的产品实现交由工厂类来完成。

简单工厂模式的UML图:
img1

简单工厂类的实现:

public class FruitFactory {
    public static Fruit createFruit(int type) {
        switch (type) {
            case 1:
                return new Apple();
            case 2:
                return new Pear();
            case 3:
                return new Banana();
        }
        return null;
    }
}

简单工厂类的使用:

public class Client {
    public static void main(String[] args) {
        Fruit apple = FruitFactory.createFruit(1);
        apple.grow();
        apple.harvest();

        Fruit pear = FruitFactory.createFruit(2);
        pear.grow();
        pear.harvest();

        Fruit banana = FruitFactory.createFruit(3);
        banana.grow();
        banana.harvest();
    }
}

另一种简单工厂的实现:

public class FruitFactory2 {
    public static <T extends Fruit> T createFruit(Class<T> clz) {
        try {
            return (T) Class.forName(clz.getName()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

打印结果:

apple is growing
apple is harvested
Pear is growing
Pear is harvested
Banana is growing
Banana is harvested

简单工厂的扩展

简单工厂还可以对所要创建的对象进行管理,比如,对所创建的对象进行缓存,从而达到单例的效果。

工厂模式实现单例的代码示例:

public class FruitFactory3 {
    private static Map<Integer, Fruit> fruitObj = new HashMap<>();

    public static Fruit createFruit(int type) {
        if (fruitObj.get(type) != null) {
            return fruitObj.get(type);
        }

        Fruit fruit = null;

        switch (type) {
            case 1:
                fruit = new Apple();
                break;
            case 2:
                fruit = new Pear();
                break;
            case 3:
                fruit = new Banana();
                break;
        }
        fruitObj.put(type, fruit);
        return fruit;
    }
}

简单工厂的优点

  1. 工厂的使用者不需要关心具体对象的创建过程,符合迪米特的最少知道原则;同时,由于只关心接口而不关注具体的实现类,符合依赖倒置原则;又使用父类(这里指接口)的地方,可以无缝的替换成子类,符合里氏替换原则。
  2. 工厂可以非常灵活的对所要创建的对象进行管理,可以方便的对所创建对象的数量进行控制,比如:对多对象实现单例。

简单工厂的缺点

  1. 对于扩展不太友好,如果增加了一个新的水果,工厂中的静态方法就需要被修改,而这违背了开闭原则,对扩展开放,对修改关闭。

工厂方法模式

工厂方法可以说是对简单工厂缺点的一个修复,在工厂中引入了抽象方法,具体的实现由各个具体产品的工厂来实现。这样一来,在新增同类产品时,就需要对抽象方法进行扩展。

工厂方法模式UML图:
img1

工厂方法定义

定义一个创建对象的接口,由子类决定实例化哪个类。
工厂方法使对象的实例化延迟到了子类。

工厂方法抽象类:

public abstract class AbstractFactory {
    protected abstract Fruit createFruit();
}

相对应的具体工厂的实现:

public class AppleFactory extends AbstractFactory {
    @Override
    protected Fruit createFruit() {
        return new Apple();
    }
}


public class PearFactory extends AbstractFactory {
    @Override
    protected Fruit createFruit() {
        return new Pear();
    }
}

public class BananaFactory extends AbstractFactory {
    @Override
    protected Fruit createFruit() {
        return new Banana();
    }
}

工厂类的使用者:

public class client {
    public static void main(String[] args) {

        AppleFactory appleFactory = new AppleFactory();
        Fruit fruit = appleFactory.createFruit();
        fruit.grow();
        fruit.harvest();
    }
}

需要创建哪一类的水果就使用与之相对应的工厂类来进行创建。然后,调用相应的方法即可。

工厂方法的扩展

当我们增加了一种新的水果橙子,我们只需要创建一个橙子类来实现产品接口,同时创建一个生产橙子的工厂实现抽象工厂中的方法即可。

public class OrangeFactory extends AbstractFactory {
    @Override
    protected Fruit createFruit() {
        return new Orange();
    }
}


public class Orange implements Fruit {
    @Override
    public void grow() {
        System.out.println("orange is growing");
    }

    @Override
    public void harvest() {
        System.out.println("orange is harvested");
    }
}

工厂方法存在的问题

当工厂方法创建的不是一类产品,而是多类产品时,我们的工厂类的数量会成倍的增加,也就是会有多类产品的工厂等级结构。多类工厂来解决多类产品对象的创建问题,这样,显然是比较臃肿的,而好的解决此类问题的方式,是一类工厂来解决多类产品对象的创建,这个就需要使用抽象工厂模式来解决了。

工厂方法的优点

  1. 解决了简单工厂需要修改原有代码的问题,更方便于扩展。
  2. 屏蔽具体的产品实现类,使用者只需要关注产品的接口,只要接口保持不变,系统的上层调用就保持不变。

工厂方法的缺点

  1. 当要为多类产品创建对象时,(比如上面的例子中我们添加一个颜色作为一类新的产品,现在的水果有很多种颜色嘛。也就是说水果和颜色是两类不同的产品,但是从横向看,它们是一系列相关的产品,可以组成产品簇)。使用工厂方法就会显得非常的臃肿,代码量大增,而且不利于扩展。

抽象工厂模式

产品簇

要理解抽象工厂模式,首先需要理解产品簇的概念。那什么是产品簇呢?产品簇就在不同的产品等级结构中,功能相关联的产品所组成的家族。这个要怎么理解呢?需要从横向和纵向两个维度来理解产品簇的概念。

img1
横向的表示产品等级结构,表示同类的产品;纵向的表示产品簇。只要为一个产品指明它所对应的产品簇及其对应的层级结构中,就可以唯一的确定这个产品。

抽象工厂模式定义

为创建一组相关或者相互依赖的对象提供一个接口,并且不用指定它们的具体实现。

抽象工厂的UML图:

img1

这里引入了颜色作为一类产品,也就是uml图里除了有水果的层级结构外,多了一类颜色的层级结构。而由一类工厂的层级结构来解决两类层级结构的问题。每一个具体的工厂,分别由两个方法组成,而这两个方法分别为两个不同类的层级结构创建对象,而组成产品簇。也就是具体的工厂,实际上负责一类产品簇对象的创建。

新增加的颜色类的代码结构为:

public interface Color {
    void currentColor();
}

public class GreenColor implements Color {
    @Override
    public void currentColor() {
        System.out.println("Green color");
    }
}


public class RedColor implements Color {
    @Override
    public void currentColor() {
        System.out.println("red color");
    }
}


public class YellowColor implements Color {
    @Override
    public void currentColor() {
        System.out.println("Yellow color");
    }
}

对应的工厂的代码为:

public abstract class AbstractFactory {
    protected abstract Fruit createFruit();

    protected abstract Color getColor();
}

public class GreenPearFactory extends AbstractFactory {
    @Override
    protected Fruit createFruit() {
        return new Pear();
    }

    @Override
    protected Color getColor() {
        return new GreenColor();
    }
}

public class RedAppleFactory extends AbstractFactory {
    @Override
    protected Fruit createFruit() {
        return new Apple();
    }

    @Override
    protected Color getColor() {
        return new RedColor();
    }
}

public class YellowBananaFactory extends AbstractFactory {
    @Override
    protected Fruit createFruit() {
        return new Banana();
    }

    @Override
    protected Color getColor() {
        return new YellowColor();
    }
}

最终使用工厂的场景类为:

public class Client {
    public static void main(String[] args) {
        RedAppleFactory redAppleFactory = new RedAppleFactory();
        Fruit fruit = redAppleFactory.createFruit();
        fruit.grow();
        fruit.harvest();

        Color appColor = redAppleFactory.getColor();
        appColor.currentColor();
    }
}

打印结果为:

apple is growing
apple is harvested
red color

到这里,我们就完成了使用一个层级结构的工厂类解决了两种不同类型,各自拥有其特定层级结构的类创建包含特定关系的一组对象。

抽象工厂的优点

  1. 使得纵向扩展变得容易,如果添加一种水果或者颜色,只需要创建一个颜色和水果组成的工厂类继承自抽象工厂,就完成了对象的新增。

抽象工厂的缺点

  1. 增加了创建产品的复杂度。如果需要横向再多扩展一个新的类型,那么,就需要扩展一个新的类型,并修改抽象工厂里的方法,这样就违反了开闭原则,而且,代码量也成倍增加。

总结

工厂模式是在开发中用到非常频繁的一种设计模式,正确认识到三种工厂所应用的场景,有利于我们在开发中更好的使用好相对应的工厂,来解决实际问题。作为一种简单的创建类设计模式,熟练掌握其使用是程序员必备的技能。