天天看点

一篇文章掌握工厂模式

一.一个实际的案例(原始版)

1.需求

一篇文章掌握工厂模式

2.UML类图

一篇文章掌握工厂模式

3.具体代码

(1)Pizza抽象类

//将pizza做成抽象类
public abstract class Pizza {
    protected String name;

    public abstract void prepare();
    public void bake(){
        System.out.println(name + "baking");
    }
    public void cut(){
        System.out.println(name + "cuting");
    }
    public void box(){
        System.out.println(name + "box");
    }

    public void setName(String name){
        this.name = name;
    }
}      

(2)GreekPizza

public class GreekPizza extends Pizza{
    @Override
    public void prepare() {
        System.out.println("为制作希腊披萨制作原材料");
    }
}      

(3)CheesePizza

public class CheesePizza extends Pizza{
    @Override
    public void prepare() {
        System.out.println("为制作奶酪披萨准备原材料");
    }
}      

(4)OrderPizza

public class OrderPizza {
    OrderPizza(){
        Pizza pizza = null;
        String orderType;
        do{
            orderType = getType();
            if(orderType.equals("greek")){
                pizza = new GreekPizza();
                pizza.setName("希腊披萨");
            }else if(orderType.equals("cheese")){
                pizza = new CheesePizza();
                pizza.setName("奶酪披萨");
            }else {
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }while (true);
    }
    private String getType(){
        try{
            BufferedReader string = new BufferedReader((new InputStreamReader(System.in)));
            System.out.println("input pizza type:");
            String str = string.readLine();
            return str;
        }catch (IOException e){
            e.printStackTrace();
            return "";
        }

    }
}      

(5)PizzaStore

public class PizzaStore {
    public static void main(String[] args) {
        new OrderPizza();
    }
}      

4.此种方法优缺点分析

(1)优点

比较好理解,简单易操作

(2)缺点

违反了设计模式的ocp原则,即对扩展开放,对修改关闭,即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码

(3)比如新增一个胡椒披萨类,则需要修改的地方有

新增一个胡椒披萨类

public class PepperPizza extends Pizza{
    @Override
    public void prepare() {
        System.out.println("正在准备胡椒披萨");
    }
}      

在OrderPizza里面增加一个新判断

else if(orderType.equals("pepper")){
                pizza = new PepperPizza();
                pizza.setName("胡椒披萨");      

5.改进思路

(1)分析

修改一小部分的代码当然可以接收,但是如果我们在其他的地方也有创建Pizza的代码时,就意味着也需要修改,而创建Pizza的代码往往不止一处。

(2)思路

把创建Pizza对象封装到一个类中,这样我们有新的Pizza种类时,只需要修改该类即可,其他有创建Pizza对象的代码就不需要修改了。------------------------>简单工厂模式

二.简单工厂模式(静态工厂模式)

1.基本介绍

简单工厂模式属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式。

简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为

在软件开发中,当我们会用到大量的创建某种、某类或某批对象时,就会使用到工厂模式

有时简单工厂模式也被称为静态工厂模式,因为createPizza这样的方法有可能是静态的

2.UML类图

一篇文章掌握工厂模式

3.上述实例改进后的代码

SimpleFactory

//简单工厂类
public class SimpleFactory {
    public Pizza createPizza(String orderType){
        Pizza pizza = null;

        System.out.println("使用简单工厂模式");
        if(orderType.equals("greek")){
            pizza = new GreekPizza();
            pizza.setName("希腊披萨");
        }else if(orderType.equals("cheese")){
            pizza = new CheesePizza();
            pizza.setName("奶酪披萨");
        }else if(orderType.equals("pepper")){
            pizza = new PepperPizza();
            pizza.setName("胡椒披萨");
        }
        return pizza;
    }
}      

OrderPizza

public class OrderPizza {
    //定义一个简单工厂对象
    SimpleFactory simpleFactory;
    Pizza pizza = null;

    OrderPizza(SimpleFactory simpleFactory){
        setFactory(simpleFactory);
    }

    public void setFactory(SimpleFactory simpleFactory){
        String orderType="";//由用户输入

        this.simpleFactory = simpleFactory;


        do {
            orderType = getType();
            pizza = simpleFactory.createPizza(orderType);

            if(pizza != null){
                System.out.println("订购成功");
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else {
                System.out.println("订购披萨失败");
                break;
            }
        }while (true);
    }

    private String getType(){
        try{
            BufferedReader string = new BufferedReader((new InputStreamReader(System.in)));
            System.out.println("input pizza type:");
            String str = string.readLine();
            return str;
        }catch (IOException e){
            e.printStackTrace();
            return "";
        }

    }
}      

PizzaStore

public class PizzaStore {
    public static void main(String[] args) {
       new OrderPizza(new SimpleFactory());
       System.out.println("退出了程序");
    }
}      
input pizza type:
cheese
使用简单工厂模式
订购成功
为制作奶酪披萨准备原材料
奶酪披萨baking
奶酪披萨cuting
奶酪披萨box
input pizza type:      

三.工厂方法模式

1.引例

假如有一个新的需求

客户在点披萨时,可以点不同口味的披萨,比如北京的奶酪披萨,北京的胡椒披萨。伦敦的奶酪披萨,伦敦的胡椒披萨。

思路1

使用简单工厂模式,创建类似于BJPizzaSimpleFactory、LDPizzaSimpleFactory这样的简单工厂类,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好。

思路2

使用工厂方法模式

2.工厂方法模式介绍

定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类

关于此案例,工厂方法模式的设计方案

将披萨的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。

3.UML类图

一篇文章掌握工厂模式

4.具体代码

LDXXXX和BJXXXX基本是一样的,所以在这里只列出了BJXXXX的

OrderPizza

public abstract class OrderPizza {
    //定义一个抽象方法,让各个工厂子类自己实现
    public abstract Pizza createPizza(String orderType);

    OrderPizza(){
        Pizza pizza = null;
        String orderType;
        do{
            orderType = getType();
            pizza = createPizza(orderType);//具体是调用的子类的创建方法
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }while (true);
    }
    private String getType(){
        try{
            BufferedReader string = new BufferedReader((new InputStreamReader(System.in)));
            System.out.println("input pizza type:");
            String str = string.readLine();
            return str;
        }catch (IOException e){
            e.printStackTrace();
            return "";
        }

    }
}      

BJOrderPizza

public class BJOrderPizza extends OrderPizza{
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")){
            pizza = new BJCheesePizza();
        }else if(orderType.equals("pepper")){
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}      

BJCheesePizza

public class BJCheesePizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京奶酪披萨");
        System.out.println("为制作北京奶酪披萨准备原材料");
    }
}      

BJPepperPizza

public class BJPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京胡椒披萨");
        System.out.println("正在准备北京胡椒披萨");
    }
}      

PizzaStore

public class PizzaStore {
    public static void main(String[] args) {
       //创建北京口味的各种披萨
       new BJOrderPizza();
       System.out.println("退出了程序");
    }
}      
cheese
为制作北京奶酪披萨准备原材料
北京奶酪披萨baking
北京奶酪披萨cuting
北京奶酪披萨box
input pizza type:
pepper
正在准备北京胡椒披萨
北京胡椒披萨baking
北京胡椒披萨cuting
北京胡椒披萨box
input pizza type:
sadad
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.day09.Pizza.prepare()" because "pizza" is null
  at com.day09.OrderPizza.<init>(OrderPizza.java:17)
  at com.day09.BJOrderPizza.<init>(BJOrderPizza.java:3)
  at com.day09.PizzaStore.main(PizzaStore.java:6)      

程序的执行过程

在PizzaStore 中创建BJOrderPizza,因为BJOrderPizza继承了OrderPizza,先有父类后有子类,所以进入OrderPizza的构造方法中

OrderPizza(){
        Pizza pizza = null;
        String orderType;
        do{
            orderType = getType();
            pizza = createPizza(orderType);//具体是调用的子类的创建方法
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }while (true);
    }      

在构造方法中,createPizza是抽象方法,由BJOrderPizza实现,所以调用的是BJOrderPizza的createPizza方法,

@Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")){
            pizza = new BJCheesePizza();
        }else if(orderType.equals("pepper")){
            pizza = new BJPepperPizza();
        }
        return pizza;
    }      

当我们输入cheese的时候,就创建相应的BJCheesePizza,在OrderPizza的构造方法中得到,然后进行prepare、bake、cut、box。

四.抽象工厂模式

1.基本介绍

定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类

抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合

从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)

将工厂抽象成两层,即AbsFactory(抽象工厂)和具体实现的工厂子类。

程序员可以根据创建对象类型使用对应的工厂子类。这样就将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。

2.UML类图

一篇文章掌握工厂模式

3.具体代码

AbsFactory

//一个抽象工厂模式的抽象层(接口)
public interface AbsFactory {
    //让下面的工厂子类来具体实现
    public Pizza createPizza(String orderType);
}      

OrderPizza

public class OrderPizza {
    AbsFactory absFactory;
    public OrderPizza(AbsFactory factory){
        setFactory(factory);
    }
    private void setFactory(AbsFactory factory){
        Pizza pizza = null;
        String orderType;
        absFactory = factory;
        do{
            orderType = getType();
            pizza = factory.createPizza(orderType);
            if(pizza != null){
                System.out.println("预定成功");
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else {
                System.out.println("订购失败");
                break;
            }

        }while (true);
    }

    private String getType(){
        try{
            BufferedReader string = new BufferedReader((new InputStreamReader(System.in)));
            System.out.println("input pizza type:");
            String str = string.readLine();
            return str;
        }catch (IOException e){
            e.printStackTrace();
            return "";
        }

    }
}      

BJFactory

public class BJFactory implements AbsFactory{
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")){
            pizza = new BJCheesePizza();
        }else if(orderType.equals("pepper")){
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}      

PizzaStore

public class PizzaStore {
    public static void main(String[] args) {
       //创建北京口味的各种披萨
       new OrderPizza(new BJFactory());
       System.out.println("退出了程序");
    }
}      
input pizza type:
cheese
预定成功
为制作北京奶酪披萨准备原材料
北京奶酪披萨baking
北京奶酪披萨cuting
北京奶酪披萨box
input pizza type:
pepper
预定成功
正在准备北京胡椒披萨
北京胡椒披萨baking
北京胡椒披萨cuting
北京胡椒披萨box
input pizza type:
sadasdsad
订购失败
退出了程序

Process finished with exit code 0      

五.总结

1.工厂模式的意义

2.三种工厂模式

3.体现了设计模式的依赖抽象原则

(1)创建对象实例时,不要直接new类,而是把这个new类的动作放在一个工厂的方法中,并返回。有的书上说,变量不要直接持有具体类的引用。
(2)不要让类继承具体类,而是继承抽象类或者实现接口
(3)不要覆盖基类(一般是抽象类)中已实现的方法