设计模式之工厂模式

115 阅读3分钟

工厂模式是常用的实例化对象的方法,可以用工厂方法代替new操作。我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。在实际使用中,传入对应的参数即可。

工厂模式可以分为三类:简单工厂模式、工厂方法模式和抽象工厂模式。

一、简单工厂模式

首先,我们创建一个接口Fruit,接口中一个抽象方法,用来打印水果的颜色:

public interface Fruit {
    void color();
}

之后可以用创建两个实体类,Apple类和Banana类实现工厂接口:

public class Apple implements Fruit{
    @Override
    public void color() {
        System.out.println("color is red");
    }
}
public class Banana implements Fruit{
    @Override
    public void color() {
        System.out.println("color is yellow");
    }
}

创建一个工厂类,根据不同的参数,new不同的对象:

public class FruitFactory {
    public Fruit getFruit(String name) {
        Fruit fruit = null;
        if (name.equals("banana")) {
            return new Banana();
        } else if (name.equals("Apple")) {
            return new Apple();
        }
        return null;
    }
}

使用该工厂,传入不同的参数获取不同的对象:

public class Test {
    public static void main(String[] args) {
        FruitFactory factory = new FruitFactory();
        Fruit apple = factory.getFruit("apple");
        Fruit banana = factory.getFruit("banana");
        apple.color();
        banana.color();
    }
}

简单工厂方法的缺点是每增加一个水果,就要在工厂中增加一个类,适合用于类比较少的情况。

二、工厂方法模式

工厂方法模式对简单工厂模式进一步改进,可以在不修改原有代码的情况下引进新的水果,符合开闭原则。增加一个抽象工厂:

public interface FruitFactory {
    Fruit getFruit();
}

针对苹果和香蕉,分别增加两个两个工厂类实现这个工厂接口:

public class AppleFactory implements FruitFactory{

    @Override
    public Fruit getFruit() {
        return new Apple();
    }
}
public class BananaFactory implements FruitFactory{

    @Override
    public Fruit getFruit() {
        return new Banana();
    }
}

调用具体工厂获取具体的水果:

public static void main(String args[]) {
    FruitFactory appleFactory = new AppleFactory();
    FruitFactory bananaFactory = new BananaFactory();
    Fruit apple = appleFactory.getFruit();
    Fruit banana = bananaFactory.getFruit();
    apple.color();
    banana.color();
}

工厂方法模式的缺点是一种具体工厂只能生产一种具体的类,如果类的种类过多,会造成代码过于复杂。

三、抽象工厂模式

抽象工厂模式,创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。这种模式将多个产品合并成一个产品族。再通过产品族下面的工厂去获取具体的某一类产品。

原有的水果接口保持不变,创建蔬菜接口:

public interface Vegetables {
    void getShape();
}

创建两个实体类Cucumber和Tomato,实现蔬菜接口

public class Cucumber implements Vegetables{

    @Override
    public void getShape() {
        System.out.println("strip");
    }
}
public class Tomato implements Vegetables {

    @Override
    public void getShape() {
        System.out.println("globular");
    }
}

创建抽象工厂FoodFactory,用来获取工厂:

public interface FoodFactory {
    Fruit getFruit(String fruit);
    Vegetables getVegetables(String vegetables);
}

创建实现了抽象工厂FoodFactory的具体工厂类,基于给定的信息生成对象:

public class FruitFactory implements FoodFactory{

    @Override
    public Fruit getFruit(String fruit) {
        if (fruit.equals("apple")) {
            return new Apple();
        } else if (fruit.equals("banana")) {
            return new Banana();
        }
        return null;
    }

    @Override
    public Vegetables getVegetables(String vegetables) {
        return null;
    }
}
public class VegetablesFactory implements FoodFactory {

    @Override
    public Fruit getFruit(String fruit) {
        return null;
    }

    @Override
    public Vegetables getVegetables(String vegetables) {
        if (vegetables.equals("cucumber")) {
            return new Cucumber();
        } else if (vegetables.equals("tomato")) {
            return new Tomato();
        }
        return null;
    }
}

创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂:

public class FactoryProduce {
    public static FoodFactory getFactory(String choice) {
        if (choice.equals("fruit")) {
            return new FruitFactory();
        } else if (choice.equals("vegetables")) {
            return new VegetablesFactory();
        }
        return null;
    }
}

先获取具体的工厂,再通过工厂获取具体的类:

public static void main(String[] args) {

    FoodFactory fruitFactory = FactoryProduce.getFactory("fruit");
    Fruit fruit = fruitFactory.getFruit("apple");
    fruit.color();

    FoodFactory vegetablesFactory = FactoryProduce.getFactory("vegetables");
    Vegetables vegetables = vegetablesFactory.getVegetables("tomato");
    vegetables.shape();
}