简单工厂模式、工厂方法模式、抽象工厂模式

我们现在需要建一个能够制作披萨的程序,这里面有不同口味的披萨,同时还有披萨的所有步骤,这里给出了四个步骤(准备,烘烤,切割,打包)。

 

我们在不使用简单工厂模式的时候

package com.factory.simplefactory.pizzastore.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 + " cutting");
    }

    /**
     * 打包
     */
    public void box() {
        System.out.println(name + " boxing");
    }

    public String getName() {
        return name;
    }

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

  

package com.factory.simplefactory.pizzastore.pizza;

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

  

package com.factory.simplefactory.pizzastore.pizza;

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

  

package com.factory.simplefactory.pizzastore.order;

import com.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.factory.simplefactory.pizzastore.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class OrderPizza {
    //创建一个构造器
    public OrderPizza() {
        Pizza pizza=null;
        String orderType="";//订购的披萨类型
        do {
            orderType=getType();
            if("greek".equals(orderType)){
                pizza=new GreekPizza();
                pizza.setName("希腊披萨");
            }else if("cheese".equals(orderType)){
                pizza=new CheesePizza();
                pizza.setName("奶酪披萨");
            }else {
                break;
            }
            //输出披萨的制作过程
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }while (true);
    }

    //获取客户希望订购的披萨种类
    private String getType(){
        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("请输入您想订购的披萨种类:");
            String str = bufferedReader.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return e.toString();
        }
    }
}

  

package com.factory.simplefactory.pizzastore.order;

/**
 * 相当于一个客户端,发出订购
 */
public class PizzaStore {
    public static void main(String[] args) {
        new OrderPizza();
    }
}

  

运行结果:

请输入您想订购的披萨种类:
greek
给制作希腊披萨准备原材料
希腊披萨 baking
希腊披萨 cutting
希腊披萨 boxing
请输入您想订购的披萨种类:
cheese
给制作奶酪披萨准备原材料
奶酪披萨 baking
奶酪披萨 cutting
奶酪披萨 boxing
请输入您想订购的披萨种类:
yyy
订购披萨失败!!!
程序运行结束

  

分析一下这种方法的缺点

 

 

假设我们订购pizza的店铺有很多(说白了,在实际项目中,订购pizza的这个功能有很多系统都在调用)当我们需要增加一种pizza的时候,就会出现OrderPizza1OrderPizza2OrderPizza3等等类都需要修改(好比是好些个订阅pizza的系统都要因为你增加了一款pizza而修改自己系统的代码),这在实际项目开发中肯定是不现实的。当然这种写法也有他的好处就是:便于理解,仅此而已。

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

 

简单工厂模式

 

  1. 简单工厂模式属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,简单工厂模式是工厂模式家族中最简单实用的模式。
  2. 简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为。
  3. 在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式。

 

 

对上面的程序进行改进:

package com.factory.simplefactory.pizzastore.order;

import com.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.factory.simplefactory.pizzastore.pizza.Pizza;

/**
 * 简单工厂类
 */
public class SimpleFactory {
    //传入orderType,返回对应的Pizza
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        System.out.println("使用简单工厂模式");
        if ("greek".equals(orderType)) {
            pizza = new GreekPizza();
            pizza.setName("希腊披萨");
        } else if ("cheese".equals(orderType)) {
            pizza = new CheesePizza();
            pizza.setName("奶酪披萨");
        } else if("pepper".equals(orderType)){
            pizza = new PepperPizza();
            pizza.setName("胡椒披萨");
        }
        return pizza;
    }

}

  

package com.factory.simplefactory.pizzastore.order;

import com.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.factory.simplefactory.pizzastore.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class OrderPizza {

    SimpleFactory simpleFactory = null;
    Pizza pizza = null;

    //添加构造方法
    public OrderPizza(SimpleFactory simpleFactory) {
        setFactory(simpleFactory);
    }
    public void setFactory(SimpleFactory simpleFactory){
        this.simpleFactory = simpleFactory;//设置简单工厂对象
        String orderType = "";//用户输入的
        do {
            orderType = getType();
            pizza = this.simpleFactory.createPizza(orderType);
            //输出披萨的制作过程
            if (null != pizza) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else {
                System.out.println("订购披萨失败!!!");
                break;
            }
        } while (true);
    }

    //获取客户希望订购的披萨种类
    private String getType() {
        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("请输入您想订购的披萨种类:");
            String str = bufferedReader.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return e.toString();
        }
    }
}

  

我们再添加一个胡椒pizza

package com.factory.simplefactory.pizzastore.pizza;

public class PepperPizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("给制作胡椒披萨准备原材料");
    }
}

  

package com.factory.simplefactory.pizzastore.order;

import javax.sound.midi.Soundbank;

/**
 * 相当于一个客户端,发出订购
 */
public class PizzaStore {
    public static void main(String[] args) {
        new OrderPizza(new SimpleFactory());
        System.out.println("程序运行结束");
    }
}

  

运行结果:

请输入您想订购的披萨种类:
greek
使用简单工厂模式
给制作希腊披萨准备原材料
希腊披萨 baking
希腊披萨 cutting
希腊披萨 boxing
请输入您想订购的披萨种类:
pepper
使用简单工厂模式
给制作胡椒披萨准备原材料
胡椒披萨 baking
胡椒披萨 cutting
胡椒披萨 boxing
请输入您想订购的披萨种类:
cheese
使用简单工厂模式
给制作奶酪披萨准备原材料
奶酪披萨 baking
奶酪披萨 cutting
奶酪披萨 boxing
请输入您想订购的披萨种类:
yyy
使用简单工厂模式
订购披萨失败!!!
程序运行结束

  

简单工厂模式也叫做静态工厂模式。

当然也可以对上面的简单工厂模式换一种静态的方式来体现。

package com.factory.simplefactory.pizzastore.order;

import com.factory.simplefactory.pizzastore.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class OrderPizza2 {

    Pizza pizza = null;

    //添加构造方法
    public OrderPizza2() {
        String orderType = "";//用户输入的
        do {
            orderType = getType();
            pizza = SimpleFactory.createPizza2(orderType);
            //输出披萨的制作过程
            if (null != pizza) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else {
                System.out.println("订购披萨失败!!!");
                break;
            }
        } while (true);
    }

    //获取客户希望订购的披萨种类
    private String getType() {
        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("请输入您想订购的披萨种类:");
            String str = bufferedReader.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return e.toString();
        }
    }
}

  

package com.factory.simplefactory.pizzastore.order;

import com.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.factory.simplefactory.pizzastore.pizza.Pizza;

/**
 * 简单工厂类
 */
public class SimpleFactory {

    //传入orderType,返回对应的Pizza
    public static Pizza createPizza2(String orderType) {
        Pizza pizza = null;
        System.out.println("使用简单工厂模式2");
        if ("greek".equals(orderType)) {
            pizza = new GreekPizza();
            pizza.setName("希腊披萨");
        } else if ("cheese".equals(orderType)) {
            pizza = new CheesePizza();
            pizza.setName("奶酪披萨");
        } else if("pepper".equals(orderType)){
            pizza = new PepperPizza();
            pizza.setName("胡椒披萨");
        }
        return pizza;
    }

}

  

package com.factory.simplefactory.pizzastore.order;

        import javax.sound.midi.Soundbank;

/**
 * 相当于一个客户端,发出订购
 */
public class PizzaStore {
    //    public static void main(String[] args) {
//        new OrderPizza();
//    }
    public static void main(String[] args) {
        new OrderPizza2();
        System.out.println("程序运行结束");
    }
}

  

运行结果:

请输入您想订购的披萨种类:
greek
使用简单工厂模式2
给制作希腊披萨准备原材料
希腊披萨 baking
希腊披萨 cutting
希腊披萨 boxing
请输入您想订购的披萨种类:
cheese
使用简单工厂模式2
给制作奶酪披萨准备原材料
奶酪披萨 baking
奶酪披萨 cutting
奶酪披萨 boxing
请输入您想订购的披萨种类:
pepper
使用简单工厂模式2
给制作胡椒披萨准备原材料
胡椒披萨 baking
胡椒披萨 cutting
胡椒披萨 boxing
请输入您想订购的披萨种类:
yyy
使用简单工厂模式2
订购披萨失败!!!
程序运行结束

  

工厂方法模式:

看一个新的需求:客户在点披萨的时,可以点不同口味的披萨,比如北京的奶酪pizza、北京的胡椒pizza或者是伦敦的奶酪pizza、路通的胡椒pizza

思路1;

使用简单工厂模式,创建不同的简单工厂类,比如BJPizzaSimpleFactoryLDPizzaSimpleFactory等等,从当前这个案例来说,也是可的,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好。

思路2

使用工厂方法模式。

工厂方法模式:

工厂方法模式介绍

工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。

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

package com.factory.factorymethod.pizzasotre;

/**
 * 披萨抽象类
 */
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 + " cutting");
    }

    /**
     * 打包
     */
    public void box() {
        System.out.println(name + " boxing");
    }

    public String getName() {
        return name;
    }

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

  

package com.factory.factorymethod.pizzasotre;

public class LDPepperPizza extends Pizza {

    @Override
    public void prepare() {
        setName("伦敦的胡椒pizza");
        System.out.println("伦敦胡椒披萨准备");
    }
}

  

package com.factory.factorymethod.pizzasotre;

public class LDCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("伦敦的奶酪pizza");
        System.out.println("伦敦奶酪披萨准备");
    }
}

  

package com.factory.factorymethod.pizzasotre;

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

  

package com.factory.factorymethod.pizzasotre;



public class BJCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("北京的奶酪pizza");
        System.out.println("北京奶酪披萨准备");
    }
}

  

package com.factory.factorymethod.order;

import com.factory.factorymethod.pizzasotre.BJCheesePizza;
import com.factory.factorymethod.pizzasotre.BJPepperPizza;
import com.factory.factorymethod.pizzasotre.Pizza;

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

  

package com.factory.factorymethod.order;

import com.factory.factorymethod.pizzasotre.*;

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

  

package com.factory.factorymethod.order;

public class PizzaStore {
    public static void main(String[] args) {
        //创建北京口味的各种pizza
        new BJOrderPizza();
        //创建伦敦口味的各种pizza
//        new LDOrderPizza();
    }
}

  

运行结果;

请输入您想订购的披萨种类:
cheese
北京奶酪披萨准备
北京的奶酪pizza baking
北京的奶酪pizza cutting
北京的奶酪pizza boxing
请输入您想订购的披萨种类:
pepper
北京胡椒披萨准备
北京的胡椒pizza baking
北京的胡椒pizza cutting
北京的胡椒pizza boxing
请输入您想订购的披萨种类:
greek
订购披萨失败!!!

  

抽象工厂模式
基本介绍
1)抽象工厂模式:定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类。
2)抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
3)从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者成为进一步的抽象)。
4)将工厂抽象成两层,AbsFactory(抽象工厂)和具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,跟利于代码的维护和扩展。

  

 

 

在这个基础上,我们又新增了地址信息的分类,即有北京口味的pizza 和 伦敦口味的pizza

 

package com.factory.absfactory.pizzastore.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 + " cutting");
    }

    /**
     * 打包
     */
    public void box() {
        System.out.println(name + " boxing");
    }

    public String getName() {
        return name;
    }

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

 

  

package com.factory.absfactory.pizzastore.pizza;

public class LDPepperPizza extends Pizza {

    @Override
    public void prepare() {
        setName("伦敦的胡椒pizza");
        System.out.println("伦敦胡椒披萨准备");
    }
}

  

package com.factory.absfactory.pizzastore.pizza;

public class LDCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("伦敦的奶酪pizza");
        System.out.println("伦敦奶酪披萨准备");
    }
}

  

package com.factory.absfactory.pizzastore.pizza;

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

  

package com.factory.absfactory.pizzastore.pizza;


public class BJCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("北京的奶酪pizza");
        System.out.println("北京奶酪披萨准备");
    }
}

  

package com.factory.absfactory.pizzastore.order;

import com.factory.absfactory.pizzastore.pizza.Pizza;

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

  

package com.factory.absfactory.pizzastore.order;

import com.factory.absfactory.pizzastore.pizza.BJCheesePizza;
import com.factory.absfactory.pizzastore.pizza.BJPepperPizza;
import com.factory.absfactory.pizzastore.pizza.Pizza;

/**
 * 这是工厂类的子类
 */
public class BJFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        System.out.println("使用的是抽象工厂模式");
        Pizza pizza=null;
        if("cheese".equals(orderType)){
            pizza=new BJCheesePizza();
        }else if("pepper".equals(orderType)){
            pizza=new BJPepperPizza();
        }
        return pizza;
    }
}

  

package com.factory.absfactory.pizzastore.order;

import com.factory.absfactory.pizzastore.pizza.*;

/**
 * 这是工厂类的子类
 */
public class LDFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        System.out.println("使用的是抽象工厂模式");
        Pizza pizza=null;
        if("cheese".equals(orderType)){
            pizza=new LDCheesePizza();
        }else if("pepper".equals(orderType)){
            pizza=new LDPepperPizza();
        }
        return pizza;
    }
}

  

package com.factory.absfactory.pizzastore.order;

import com.factory.absfactory.pizzastore.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 订购pizza
 */
public class OrderPizza {
    AbsFactory factory=null;
    public OrderPizza(AbsFactory factory){
        setFactory(factory);
    }
    private void setFactory(AbsFactory factory){
        Pizza pizza=null;
        String orderType="";//用户输入
        this.factory=factory;
        do {
            orderType=getType();
            //factory 可能是北京的工厂子类,也可能是伦敦的工厂子类
            pizza = factory.createPizza(orderType);
            if(null!=pizza){
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else {
                System.out.println("订购失败");
                break;
            }

        }while (true);
    }
    //获取客户希望订购的披萨种类
    private String getType() {
        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("请输入您想订购的披萨种类:");
            String str = bufferedReader.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return e.toString();
        }
    }
}

  

package com.factory.absfactory.pizzastore.order;

public class PizzaStore {
    public static void main(String[] args) {
        new OrderPizza(new BJFactory());
//当然也可以穿伦敦工厂
    }
}

  

运行结果:

请输入您想订购的披萨种类:
cheese
使用的是抽象工厂模式
北京奶酪披萨准备
北京的奶酪pizza baking
北京的奶酪pizza cutting
北京的奶酪pizza boxing
请输入您想订购的披萨种类:
pepper
使用的是抽象工厂模式
北京胡椒披萨准备
北京的胡椒pizza baking
北京的胡椒pizza cutting
北京的胡椒pizza boxing
请输入您想订购的披萨种类:
he
使用的是抽象工厂模式
订购失败

  

工厂模式小结;

1) 工厂模式的意义

将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提供项目的扩展和维护性。

2) 三种工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)

3) 设计模式的依赖抽象原则

>创建对象实例时,不要直接new类,而是把这个new类的动作放在一个工厂的方法中,并返回。有的书上说,变量不要指直接持有具体类的引用。

>不要让类继承具体类,而是继承抽象类或者是实现interface(接口)

>不要覆盖基类中已经实现的方法。

 

posted on 2021-08-21 15:09  ~码铃薯~  阅读(48)  评论(0编辑  收藏  举报

导航