工厂模式--java实现

366 阅读4分钟

简单工厂模式

先看一个具体的需求

  1. 有一个披萨项目:要便于披萨的扩展,要便于维护。
  2. 披萨的种类很多(比如:GreekPizza、CheesePizza)
  3. 披萨的制作有prepare(准备),bake(烘焙),cut(切块),box(装盒)
  4. 完成披萨店的订购功能

传统实现方式: 类图: image.png 代码: pizza类的代码:

public abstract class Pizza {
    /**
     * 准备原材料 不同的披萨不一样 做成抽象方法
     */
    abstract void prepare();

    public void bake() {
        System.out.println(" baking");
    }

    public void cut() {
        System.out.println(" cutting");
    }

    public void box() {
        System.out.println(" boxing");
    }
}

public class CheesePizza extends Pizza {
    @Override
    void prepare() {
        System.out.println(" cheese pizza prepare");
    }
}

public class GreekPizza extends Pizza {
    @Override
    void prepare() {
        System.out.println("greek pizza prepare");
    }
}

PizzaStore代码

public class PizzaStore {
    public static void main(String[] args) {
        PizzaStore pizzaStore = new PizzaStore();
        pizzaStore.orderPizza("cheese");
        pizzaStore.orderPizza("greek");
        pizzaStore.orderPizza("pepper");
    }

    public Pizza orderPizza(String type) {
        Pizza pizza = null;
        if (type.equals("cheese")) {
            pizza = new CheesePizza();
        } else if (type.equals("greek")) {
            pizza = new GreekPizza();
        } else if (type.equals("pepper")) {
            pizza = new PepperPizza();
        }

        if (pizza != null) {
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }
        return null;
    }
}

传统方式的优缺点 - 优点是比较好理解,简单易操作·

  • 缺点是违反了设计模式的ocp原则,即外扩展开发,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者尽量少修改代码。 我们要增加一个PepperPizza时,OrderPizza类需要做如下修改
if (type.equals("cheese")) {
    pizza = new CheesePizza();
} else if (type.equals("greek")) {
    pizza = new GreekPizza();
}else if(type.equals("pepper")){
    pizza = new PepperPizza();
}

改进思路:将创建披萨对象移到orderPizza()之外,即将创建Pizza的代码移到另一个对象中,由这个新对象专职创建Pizza,这对象就称为工厂。

简单工厂类代码

public class PizzaSimpleFactory {
    public static Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new CheesePizza();
        } else if (type.equals("greek")) {
            return new GreekPizza();
        } else if (type.equals("pepper")) {
            return new PepperPizza();
        }
        return null;
    }
}

改进后的PizzaStore

public class PizzaStore {
    public static void main(String[] args) {
        PizzaStore pizzaStore = new PizzaStore();
        pizzaStore.orderPizza("cheese");
        pizzaStore.orderPizza("greek");
        pizzaStore.orderPizza("pepper");
    }

    public Pizza orderPizza(String type) {
        Pizza pizza = PizzaSimpleFactory.createPizza(type);

        if (pizza != null) {
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }
        return null;
    }
}

改进后的类图,改进前PizzaStore需要依赖具体的Pizza类型,改进后PizzaStore不用再依赖具体的pizza。

image.png 简单工厂其实不是一个设计模式,反而比较像是一种编程习惯。

工厂方法模式

  • 扩展:每个地区披萨加盟店需要提供不同风味的披萨,比如纽约需要提供纽约风味披萨,芝加哥需要提供芝加哥风味披萨。 -思路1: 利用简单工厂,可以写出不同的工厂,分别是NYStylePizzaSimpleFactory,LDStylePizzaSimpleFactory等。能满足当前扩展的需要,但是考虑到项目规模,以及软件的可维护性、可扩展性并不是特别好。
  • 思路2:使用工厂方法模式 工厂方法模式:定义了一个创建对象的接口,由子类来决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。

image.png

public abstract class PizzaStore {
    public Pizza orderPizza(String type) {
        Pizza pizza = createPizza(type);
        if (pizza != null) {
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }
        return null;
    }

    public abstract Pizza createPizza(String type);
}
public class NYStylePizzaStore extends PizzaStore {
    @Override
    public Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new NYCheesePizza();
        } else if (type.equals("greek")) {
            return new NYGreekPizza();
        } else if (type.equals("pepper")) {
            return new NYPepperPizza();
        }
        return null;
    }
}
public class PizzaOrder {
    public static void main(String[] args) {
        PizzaStore nyStylePizzaStore = new NYStylePizzaStore();
        nyStylePizzaStore.orderPizza("cheese");
        PizzaStore ldStylePizzaStore = new LDStylePizzaStore();
        ldStylePizzaStore.orderPizza("cheese");
    }
}

抽象工厂模式

  • 抽象工厂模式:定义了一个接口用于创建相关或有依赖关系的对象簇,而无需指明具体的类。
  • 抽象工厂模式可以将简单工厂模式工厂方法模式进行整合。
  • 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者进一步的抽象)。
  • 将工厂抽象为两层,AbstractFactory和具体实现的工厂子类。我们可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂变成了工厂簇,利于代码的维护和扩展。 image.png
/**
 * 抽象工厂模式的抽象层
 **/
public interface AbstractPizzaFactory {
    Pizza createPizza(String type);
}
public class NYFactory implements AbstractPizzaFactory {
    @Override
    public Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new NYCheesePizza();
        } else if (type.equals("greek")) {
            return new NYGreekPizza();
        } else if (type.equals("pepper")) {
            return new NYPepperPizza();
        }
        return null;
    }
}
public class OrderPizza {
    private AbstractPizzaFactory abstractPizzaFactory;

    public OrderPizza(AbstractPizzaFactory abstractPizzaFactory) {
        this.abstractPizzaFactory = abstractPizzaFactory;
    }

    public Pizza orderPizza(String type) {
        Pizza pizza = abstractPizzaFactory.createPizza(type);
        if (pizza != null) {
            pizza.bake();
            pizza.cut();
            pizza.box();
        }
        return pizza;
    }
}
public class PizzaStore {
    public static void main(String[] args) {
        new OrderPizza(new NYFactory()).orderPizza("cheese");
        new OrderPizza(new LDFactory()).orderPizza("cheese");
    }
}

工厂模式在JDK中的应用

public class FactoryTest {
    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        String dateInfo = String.format("%d-%d-%d %d:%d:%d", calendar.get(Calendar.YEAR),
                calendar.get(Calendar.MONTH)+1, calendar.get(Calendar.DAY_OF_MONTH),
                calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE),
                calendar.get(Calendar.SECOND));
        System.out.println(dateInfo);

    }
}

Calendar类的创建使用了工厂模式,具体可参加JDK源码