使用工厂模式加盟店,杜绝偷工减料

零.前言

HeadFirst设计模式学习笔记(1)——工厂模式
2022/7/18
2022/11/22
2022/11/27.28
2022/11/29总结

0.1.组织结构

本文的组织结构分为简单工厂模式和工厂模式,并以披萨店的品类、加盟和原料为例介绍它们。通过本文你可以学到:
● OO原则“对扩展开放对修改关闭”
● 简单工厂模式
● 工厂模式
● 构造器方式的依赖注入
● 依赖倒置原则
● 抽象工厂模式

0.2.工厂模式

工厂模式(Factory Pattern)现在是JAVA中最常用的设计模式之一。属于创建型模式,提供了一种创建对象的最佳方式。它通过一个工具类,将创建对象的具体逻辑隐藏起来,方便对外调用,也方便修改和维护。

0.3.思维导图

在这里插入图片描述


在这里插入图片描述

一、简单工厂模式

1.1.Pizza类

根据OO原则“对扩展开放,对修改关闭”,对Pizza采用抽象类/接口,通过多态与任何新类实现抽象类/该接口。

abstract class Pizza{
    String name;
    String dough;
    String sauce;

    void prepare(){
        //姓名、调料、面团之类的准备
        System.out.println("准备材料完毕!");
    }

    void bake(){
        System.out.println("bake over!");
    }
    void cut(){
        System.out.println("cut over!");
    }
    void box(){
        System.out.println("box over!");
    }

    public String getName(){
        return name;
    }

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

    public String getDough() {
        return dough;
    }

    public void setDough(String dough) {
        this.dough = dough;
    }

    public String getSauce() {
        return sauce;
    }

    public void setSauce(String sauce) {
        this.sauce = sauce;
    }
}
Pizza pizza = new Pizza();//实现的方式

披萨实例更多时,就需要判断并生成对象

if(type.equals("cheese")){//奶酪
    pizza = new CheesePizza("cheese");
}else if(type.equals("greek")){//希腊
    pizza = new GreekPizza("greek");
}else if(type.equals("pepperoni")){//香肠
    pizza = new PeppernoiPizza("pepperoni");
}

但是这种写法只有在运行时,才知道该实例化哪一个,且代码在新增/减少功能时需要多次更改。如添加type,“clam”,或者将现有需求中的"greek"删去。
提醒: 在设计模式中,“实现一个接口”并不一定表示“写一个类,并利用implement关键词来实现某个Java接口”。“实现一接口”泛指实现某个超类型(可以是类或接口)的某个方法。对Pizza采用抽象类/接口的表述也是这个意思。

1.2.SimplePizzaFactory类

建立一个简单的披萨工厂,专门负责创建这些Pizza对象。具体来说实现了简单工厂中的createPizza()方法,用这个方法来实例化新Pizza对象。
在这里插入图片描述

//SimplePizzaFactory,创建披萨
public class SimplePizzaFactory{
    public Pizza createPizza(String type){
        Pizza pizza = null;
         //上述代码段
         if(type.equals("cheese")){//奶酪
    				pizza = new CheesePizza("cheese");
				}else if(type.equals("greek")){//希腊
    				pizza = new GreekPizza("greek");
				}else if(type.equals("pepperoni")){//香肠
    				pizza = new PeppernoiPizza("pepperoni");
				}                 
    	}
}

1.3.完整代码

public class orginPizza {
    public static void main(String[] args) {//我们来个奶酪披萨
        Pizza pizza;
        SimplePizzaFactory simplePizzaFactory = new SimplePizzaFactory();
        pizza = simplePizzaFactory.createPizza("cheese");
        System.out.println(pizza.getName()+"Pizza准备完毕!");
    }
}

class SimplePizzaFactory{
    public Pizza createPizza(String type){
        Pizza pizza = null;

        if(type.equals("cheese")){
            pizza = new CheesePizza("cheese");
        }else if(type.equals("greek")){
            pizza = new GreekPizza("greek");
        }else if(type.equals("pepperoni")){
            pizza = new PeppernoiPizza("pepperoni");
        }
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}


abstract class Pizza{
    String name;
    String dough;
    String sauce;

    void prepare(){
        //姓名、调料、面团之类的准备
        System.out.println("准备材料完毕!");
    }

    void bake(){
        System.out.println("bake over!");
    }
    void cut(){
        System.out.println("cut over!");
    }
    void box(){
        System.out.println("box over!");
    }

    public String getName(){
        return name;
    }

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

    public String getDough() {
        return dough;
    }

    public void setDough(String dough) {
        this.dough = dough;
    }

    public String getSauce() {
        return sauce;
    }

    public void setSauce(String sauce) {
        this.sauce = sauce;
    }
}

/*
抽象类先继承,再实例化
 */
class CheesePizza extends Pizza{
    private String name;
    public CheesePizza(){};
    public CheesePizza(String name){
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }
}
class GreekPizza extends Pizza{
    private String name;
    public GreekPizza(){};
    public GreekPizza(String name){
        this.name = name;
    }
    @Override
    public String getName() {
        return name;
    }
}
class PeppernoiPizza extends Pizza{
    private String name;
    public PeppernoiPizza(){};
    public PeppernoiPizza(String name){
        this.name = name;
    }
    @Override
    public String getName() {
        return name;
    }
}

1.4.输出

准备材料完毕!
bake over!
cut over!
box over!
cheesePizza准备完毕!

1.5、特点

SimplePizzaFactory是一个非接口抽象类,所用的createPizza通常是静态的,所以也称作静态工厂。

1.6、缺点

1、扩展性差(改变品类如,添加type,“clam”,或者将现有需求中的"greek"删去。)
2、无法支持需要额外参数的情况,如需要新增“风格”参数,则需要更多的if,else


二、工厂模式

工厂模式即定义了一个创建对象的接口,但由子类决定要实例化的是哪一个。

2.1.披萨定义

建立PizzaStore工厂创建披萨
在这里插入图片描述
工厂调用orderPizza、然后简单工厂去调用createPizza生产披萨,而不是在PizzaFactory中直接创建披萨,这种处理也称作依赖注入,是通过构造器方式注入。

public class PizzaStore{
    SimplePizzaFactory factory;
    
    public PizzaStore(SimplePizzaFactory factory){
        this.factory = factory;    
    }
    public Pizza orderPizza(String type){
        Pizza pizza;
        pizza = factory.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

完整代码

public class orginPizza {
    public static void main(String[] args) {
        Pizza pizza;
        SimplePizzaFactory simplePizzaFactory = new SimplePizzaFactory();
        PizzaStore pizzaStore = new PizzaStore(simplePizzaFactory);
        pizza = pizzaStore.orderPizza("cheese");
        System.out.println(pizza.getName()+"Pizza准备完毕!");
    }
}
/*
* orderPizza通过简单传入类型,然后使用工厂创建比萨
* 即把new新对象的操作放在factory.createPizza(type);中
*/
class PizzaStore{
    SimplePizzaFactory factory;

    public PizzaStore(SimplePizzaFactory factory){
        this.factory = factory;
    }

    public Pizza orderPizza(String type){
        Pizza pizza;

        pizza = factory.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}
class SimplePizzaFactory{
    public Pizza createPizza(String type){
        Pizza pizza = null;

        if(type.equals("cheese")){
            pizza = new CheesePizza("cheese");
        }else if(type.equals("greek")){
            pizza = new GreekPizza("greek");
        }else if(type.equals("pepperoni")){
            pizza = new PeppernoiPizza("pepperoni");
        }
        return pizza;
    }
}
abstract class Pizza{
    String name;
    String dough;
    String sauce;

    void prepare(){
        //姓名、调料、面团之类的准备
        System.out.println("准备材料完毕!");
    }

    void bake(){
        System.out.println("bake over!");
    }
    void cut(){
        System.out.println("cut over!");
    }
    void box(){
        System.out.println("box over!");
    }

    public String getName(){
        return name;
    }

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

    public String getDough() {
        return dough;
    }

    public void setDough(String dough) {
        this.dough = dough;
    }

    public String getSauce() {
        return sauce;
    }

    public void setSauce(String sauce) {
        this.sauce = sauce;
    }
}

/*
抽象类先继承,再实例化
 */
class CheesePizza extends Pizza{
    private String name;
    public CheesePizza(){};
    public CheesePizza(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
class GreekPizza extends Pizza{
    private String name;
    public GreekPizza(){};
    public GreekPizza(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
class PeppernoiPizza extends Pizza{
    private String name;
    public PeppernoiPizza(){};
    public PeppernoiPizza(String name){
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

输出依旧不变

准备材料完毕!
bake over!
cut over!
box over!
cheesePizza准备完毕!

我们接着往下看加盟店的情况,咳咳咳,可能一些朋友看到这里突然困了,那么我们睡一会再继续看在这里插入图片描述


2.2.加盟分厂

如果在此基础上建披萨加盟店,代理不同风格的披萨
在这里插入图片描述

PizzaStore chicagoStylePizzaStore = new ChicagoStylePizzaStore();//芝加哥披萨工厂
Pizza pizza = chicagoStylePizzaStore.orderPizza("cheese");//制造披萨
2.2.1. 依赖倒置原则

依赖倒置原则:程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块之间的耦合。

PizzaStore依赖于所有的具体披萨对象,披萨具体实现的任何改变都会影响PizzaStore。每增加一个披萨种类,等于让PizzaStore多了一个依赖。
在这里插入图片描述
引入加盟分厂后,高层组件(PizzaStore)和低层组件(这些披萨)都依赖于Pizza抽象。这也是为什么称之依赖倒置原则的原因。
在这里插入图片描述

对于创建者类PizzaStore,其继承关系如下
在这里插入图片描述
我们希望orderPizza的过程是属于披萨店的一致操作,而createPizza就属于各个店分内的工作了。即将PizzaStore设计为抽象(abstract)方法,使用orderPizza()调用createPizza()。

2.2.2. 产品类Pizza

对于产品类pizza,其继承关系如下
在这里插入图片描述

2.2.3.正式开店

纽约风味分店:
(为了便于理解,减少代码量,故veggie/clam/pepperoni种类的披萨类没有创建)

class NYStylePizzaStore extends PizzaStore{
    protected Pizza createPizza(String item){
        Pizza pizza = null;
        if(item.equals("cheese")){
            return new NYStyleCheesePizza();
            //pizza.setName("New York Style Cheese Pizza");
        }else if(item.equals("veggie")){
            pizza.setName("New York Style Veggie Pizza");
        }else if(item.equals("clam")){
            pizza.setName("New York Style Clam Pizza");
        }else if(item.equals("pepperoni")){
            pizza.setName("New York Style Pepperoni Pizza");
        }
        return pizza;
    }
}
2.2.4.利用披萨工厂方法订购披萨
  • Tom和Jack需要获得披萨店的实例.Tom需要一个ChicagoPizzaStore,而Jack需要一个NYPizzaStore
PizzaStore chicagoStylePizzaStore = new ChicagoStylePizzaStore();
  • Tom和Jack分别调用orderPizza()方法,并传入他们所喜爱的披萨类型(芝士、素食…)
Pizza pizza = chicagoStylePizzaStore.orderPizza("cheese");
  • orderPizza()调用createPizza()创建披萨,其中NYPizzaStore和ChicagoPizzaStore分别实例化对应的披萨.createPizza()将创建好的披萨作为返回值.
pizza = createPizza("cheese");
  • orderPizza()像是一道加工程序,并不知道取到的是什么披萨,只是根据提供的"调料",被准备、被烘烤、被切片、被装盒,最后提供给Tom和Jack即返回披萨.
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();

具体实现披萨: 继承抽象的Pizza类,实现具体的披萨,然后赋予pizza做法。

/*
抽象类先继承,再实例化
 */
class NYStyleCheesePizza extends Pizza{
    public NYStyleCheesePizza(){
        name = "NY Style Sauce and Cheese Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";

        //toppings.add("Grated Reggiano Cheese");
    }
}

class ChicagoStyleCheesePizza extends Pizza{
    public ChicagoStyleCheesePizza() {
        name = "Chicago Style Deep Dish Cheese Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";

        //toppings.add("Shredded Mozzarella Cheese");
    }
    void cut() {
        System.out.println("Cutting the pizza into square slices");
    }
}

生产->定披萨全流程: 首先建立两个不同的店,然后用店调用orderPizza帮用户下单

public class orginPizza {
    public static void main(String[] args) {
        PizzaStore chicagoStylePizzaStore = new ChicagoStylePizzaStore();
        Pizza pizza = chicagoStylePizzaStore.orderPizza("cheese");
        System.out.println(pizza.getName()+"准备完毕!");
    }
}

2.2.5. 完整代码

我们按照需要将simplePizzaFactory改变为具体的具有不同地域风格的分厂。

public class orginPizza {
    public static void main(String[] args) {
      	//以tom为例,需要一个芝加哥的芝士
        PizzaStore chicagoStylePizzaStore = new ChicagoStylePizzaStore();
        Pizza pizza = chicagoStylePizzaStore.orderPizza("cheese");
        System.out.println(pizza.getName()+"准备完毕!");
    }
}

abstract class PizzaStore{
    public Pizza orderPizza(String type){
        Pizza pizza;

        pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
    protected abstract Pizza createPizza(String type);//Pizza的子类可以访问该函数
}

//纽约披萨分厂
//这里仅定义了NYStyleCheesePizza();
class NYStylePizzaStore extends PizzaStore{
    protected Pizza createPizza(String item){
        Pizza pizza = null;
        if(item.equals("cheese")){
            return new NYStyleCheesePizza();
            //pizza.setName("New York Style Cheese Pizza");
        }else if(item.equals("veggie")){
            pizza.setName("New York Style Veggie Pizza");
        }else if(item.equals("clam")){
            pizza.setName("New York Style Clam Pizza");
        }else if(item.equals("pepperoni")){
            pizza.setName("New York Style Pepperoni Pizza");
        }
        return pizza;
    }
}

//芝加哥披萨分厂
class ChicagoStylePizzaStore extends PizzaStore{
    protected Pizza createPizza(String item){
        Pizza pizza = null;
        if(item.equals("cheese")){
            return new ChicagoStyleCheesePizza();
            //pizza.setName("Chicago Style Cheese Pizza");
        }else if(item.equals("veggie")){
            pizza.setName("Chicago Style Veggie Pizza");
        }else if(item.equals("clam")){
            pizza.setName("Chicago Style Clam Pizza");
        }else if(item.equals("pepperoni")){
            pizza.setName("Chicago Style Pepperoni Pizza");
        }
        return pizza;
    }
}

abstract class Pizza{
    String name;
    String dough;
    String sauce;

    void prepare(){
        //姓名、调料、面团之类的准备
        System.out.println("准备材料完毕!");
    }

    void bake(){
        System.out.println("bake over!");
    }
    void cut(){
        System.out.println("cut over!");
    }
    void box(){
        System.out.println("box over!");
    }

    public String getName(){
        return name;
    }

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

    public String getDough() {
        return dough;
    }

    public void setDough(String dough) {
        this.dough = dough;
    }

    public String getSauce() {
        return sauce;
    }

    public void setSauce(String sauce) {
        this.sauce = sauce;
    }
}

/**
* 披萨子类先继承抽象类Pizza,再实例化
 */
class NYStyleCheesePizza extends Pizza{
    public NYStyleCheesePizza(){
        name = "NY Style Sauce and Cheese Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";

        //toppings.add("Grated Reggiano Cheese");
    }
}

class ChicagoStyleCheesePizza extends Pizza{
    public ChicagoStyleCheesePizza() {
        name = "Chicago Style Deep Dish Cheese Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";

        //toppings.add("Shredded Mozzarella Cheese");
    }
    void cut() {
        System.out.println("Cutting the pizza into square slices");
    }
}
**

程序输出

准备材料完毕!
bake over!
Cutting the pizza into square slices
box over!
Chicago Style Deep Dish Cheese Pizza准备完毕!

可以发现其按照自己“独特"的方式切披萨,并按照需要准备好了Chicago Style Deep Dish Cheese Pizza。
接下来才是重头戏!工厂模式粉墨登场~
在这里插入图片描述

2.3.原料工厂

2.3.1.依赖型披萨店

如若不使用工厂模式,披萨店的代码会是:

public class DependentPizzaStore{
     public Pizza createPizza(String style,Style type){
         Pizza pizza = null;
         if(style.equals("NY")){//纽约风味
             if(type.equals("cheese"))
                 pizza = new NYStyleCheesePizza();
             blabla..                                       
         } else if(style.equals("Chicago")){//芝加哥风味
             balbla..         
         }else{
             balbla..         
         }    
         pizza.prepare();
         pizza.bake();
         pizza.cut();
         ..
         return pizza;
     } 
}
2.3.2.原料家族

为了保证加盟店与主店具有相同品质的披萨,避免分店偷工减料增加利润,准备不同的材料运送到各个分店,可是分店距离太远怎么办呢?这往往难以保证每天的食材新鲜。
在这里插入图片描述
每个家族工厂都包含了一种面团、一种酱料、一种芝士、以及一种海鲜佐料,但是都各具“家族特色”。
纽约原料工厂:

/**
 * 具体的原料工厂必须实现PizzaIngredientFactory接口
 * 原料的生成方法
 * */
class NYPizzaIngredientFactory implements PizzaIngredientFactory{
    @Override
    public Dough createDough(){//这里用一种类举例
        return new ThinCrustDough();
    }
    @Override
    public Sauce createSauce() {
        return null;
    }
    @Override
    public Cheese createCheese(){
        return null;
    }

    @Override
    public Veggies[] createVeggies() {
        return new Veggies[0];
    }

    @Override
    public Pepperoni createPepperoni() {
        return null;
    }

    @Override
    public Clams createClam() {
        return null;
    }

}

重做披萨:
现在我们要使用自己的原料工厂来重新制作披萨了

/**
* Pizza类
 * 抽象类,子披萨类需要继承它
* */
abstract class Pizza{
    String name;
    String dough;
    String sauce;

    Veggies veggies[];
    Cheese cheese;
    Pepperoni pepperoni;
    Clams clam;
    void prepare(){
        //姓名、调料、面团之类的准备
        System.out.println("准备材料完毕!");
    }
    void bake(){
        System.out.println("bake over!");
    }

    void cut(){
        System.out.println("cut over!");
    }
    void box(){
        System.out.println("box over!");
    }

    public Veggies[] getVeggies() {
        return veggies;
    }

    public void setVeggies(Veggies[] veggies) {
        this.veggies = veggies;
    }

    public Cheese getCheese() {
        return cheese;
    }

    public void setCheese(Cheese cheese) {
        this.cheese = cheese;
    }

    public Pepperoni getPepperoni() {
        return pepperoni;
    }

    public void setPepperoni(Pepperoni pepperoni) {
        this.pepperoni = pepperoni;
    }

    public Clams getClam() {
        return clam;
    }

    public void setClam(Clams clam) {
        this.clam = clam;
    }

    public String getName(){
        return name;
    }

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

    public String getDough() {
        return dough;
    }

    public void setDough(String dough) {
        this.dough = dough;
    }

    public String getSauce() {
        return sauce;
    }

    public void setSauce(String sauce) {
        this.sauce = sauce;
    }
}

从今以后,加盟店必须直接从工厂取得原料,那些偷工减料的日子宣告结束了!之前写过的两个工厂方法,NYCheesePizza和ChicagoCheesePizza类,他们的差别仅仅在于使用区域性的原料,至于披萨的做法都是一样的。所以这里的两个不同的类生产不同风味的披萨是可以解耦的,让原料工厂来处理这种区域差异即可。

/**
* Pizza的子类
* */
class CheesePizza extends Pizza{
    PizzaIngredientFactory ingredientFactory;
    public CheesePizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory = ingredientFactory;
    }
    void prepare(){
        System.out.println("Preparing" + name);
        dough = String.valueOf(ingredientFactory.createDough());//面包片
        sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
        cheese = ingredientFactory.createCheese();//芝士
    }
}
class VeggiePizza extends Pizza{
    PizzaIngredientFactory ingredientFactory;
    public VeggiePizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory = ingredientFactory;
    }
    void prepare(){
        System.out.println("Preparing" + name);
        dough = String.valueOf(ingredientFactory.createDough());//面包片
        sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
        cheese = ingredientFactory.createCheese();//芝士
    }
}

class ClamPizza extends Pizza{
    PizzaIngredientFactory ingredientFactory;
    public ClamPizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory = ingredientFactory;
    }
    void prepare(){
        System.out.println("Preparing" + name);
        dough = String.valueOf(ingredientFactory.createDough());//面包片
        sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
        cheese = ingredientFactory.createCheese();//芝士
        clam = ingredientFactory.createClam();//蛤蜊
    }
}

class PepperoniPizza extends Pizza{
    PizzaIngredientFactory ingredientFactory;
    public PepperoniPizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory = ingredientFactory;
    }
    void prepare(){
        System.out.println("Preparing" + name);
        dough = String.valueOf(ingredientFactory.createDough());//面包片
        sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
        cheese = ingredientFactory.createCheese();//芝士
    }
}

现在的披萨店:

/**
* 纽约加盟店
**/
class NYPizzaStore extends PizzaStore{
    protected Pizza createPizza(String item){
        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
        if(item.equals("cheese")){
            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("New York Style Cheese Pizza");
        }else if(item.equals("veggie")){
            pizza = new VeggiePizza(ingredientFactory);
            pizza.setName("New York Style Veggie Pizza");
        }else if(item.equals("clam")){
            pizza = new ClamPizza(ingredientFactory);
            pizza.setName("New York Style Clam Pizza");
        }else if(item.equals("pepperoni")){
            pizza = new PepperoniPizza(ingredientFactory);
            pizza.setName("New York Style Pepperoni Pizza");
        }
        return pizza;
    }
}

对比前一个版本的createPizza()

public class NYPizzaStore extends PizzaStore(){
    Pizza createPizza(String item){
        if(item.equals("cheese")){
            return new NYStyleCheesePizza();        
        }else if(item.equals("veggie")){
            return new NYStyleVeggiePizza();        
        }else if(item.equals("clam")){
            return new NYStyleClamPizza();        
        }else if(item.equals("pepperoni")){
            return new NYStylePepperoniPizza();        
        }else return null;
    }
}

不同点:
原来是选择cheese,然后直接得到了NYStyleCheesePizza。而现在虽然同样是选择cheese,但是根据原料工厂来确定是NYStyleCheesePizza,进一步将原料的选择与披萨的形成抽象化了。

2.3.3.完整代码
public class IngredientFactoryExample {
    public static void main(String[] args) {
        PizzaStore nyPizzaStore = new NYPizzaStore();
        nyPizzaStore.orderPizza("cheese");
    }
}

/**
 * PizzaStore工厂
 * 抽象类,加盟店需要继承它
 * orderPizza通过简单传入类型,把new新对象的操作放在createPizza(type);中
 */
public class IngredientFactoryExample {
    public static void main(String[] args) {
        PizzaStore nyPizzaStore = new NYPizzaStore();
        Pizza pizza = nyPizzaStore.orderPizza("cheese");
        System.out.println(pizza.name + "准备完毕!");
    }
}

/**
 * PizzaStore工厂
 * 抽象类,加盟店需要继承它
 * orderPizza通过简单传入类型,把new新对象的操作放在createPizza(type);中
 */
abstract class PizzaStore{
    public Pizza orderPizza(String type){
        Pizza pizza;

        pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
    protected abstract Pizza createPizza(String type);
}

/**
* Pizza类
 * 抽象类,子披萨类需要继承它
* */
abstract class Pizza{
    String name;
    String dough;
    String sauce;

    Veggies veggies[];
    Cheese cheese;
    Pepperoni pepperoni;
    Clams clam;
    void prepare(){
        //姓名、调料、面团之类的准备
        System.out.println("准备材料完毕!");
    }
    void bake(){
        System.out.println("bake over!");
    }

    void cut(){
        System.out.println("cut over!");
    }
    void box(){
        System.out.println("box over!");
    }

    public Veggies[] getVeggies() {
        return veggies;
    }

    public void setVeggies(Veggies[] veggies) {
        this.veggies = veggies;
    }

    public Cheese getCheese() {
        return cheese;
    }

    public void setCheese(Cheese cheese) {
        this.cheese = cheese;
    }

    public Pepperoni getPepperoni() {
        return pepperoni;
    }

    public void setPepperoni(Pepperoni pepperoni) {
        this.pepperoni = pepperoni;
    }

    public Clams getClam() {
        return clam;
    }

    public void setClam(Clams clam) {
        this.clam = clam;
    }

    public String getName(){
        return name;
    }

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

    public String getDough() {
        return dough;
    }

    public void setDough(String dough) {
        this.dough = dough;
    }

    public String getSauce() {
        return sauce;
    }

    public void setSauce(String sauce) {
        this.sauce = sauce;
    }
}


/**
 * 具体的原料工厂必须实现PizzaIngredientFactory接口
 * 原料的生成方法
 * */
class NYPizzaIngredientFactory implements PizzaIngredientFactory{
    @Override
    public Dough createDough(){//这里用一种类举例
        return new ThinCrustDough();
    }
    @Override
    public Sauce createSauce() {
        return null;
    }
    @Override
    public Cheese createCheese(){
        return null;
    }

    @Override
    public Veggies[] createVeggies() {
        return new Veggies[0];
    }

    @Override
    public Pepperoni createPepperoni() {
        return null;
    }

    @Override
    public Clams createClam() {
        return null;
    }

}

/**
 * 面团类
 **/
class Dough {
}

/**
 * 面团的一种子类
 * 薄皮面团
 **/
class ThinCrustDough extends Dough{
    public void ThinCrustDough(){//构造方法
    }
}

/**
* Pizza的子类
* */
class CheesePizza extends Pizza{
    PizzaIngredientFactory ingredientFactory;
    public CheesePizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory = ingredientFactory;
    }
    void prepare(){
        System.out.println("Preparing" + name);
        dough = String.valueOf(ingredientFactory.createDough());//面包片
        sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
        cheese = ingredientFactory.createCheese();//芝士
    }
}
class VeggiePizza extends Pizza{
    PizzaIngredientFactory ingredientFactory;
    public VeggiePizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory = ingredientFactory;
    }
    void prepare(){
        System.out.println("Preparing" + name);
        dough = String.valueOf(ingredientFactory.createDough());//面包片
        sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
        cheese = ingredientFactory.createCheese();//芝士
    }
}

class ClamPizza extends Pizza{
    PizzaIngredientFactory ingredientFactory;
    public ClamPizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory = ingredientFactory;
    }
    void prepare(){
        System.out.println("Preparing" + name);
        dough = String.valueOf(ingredientFactory.createDough());//面包片
        sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
        cheese = ingredientFactory.createCheese();//芝士
        clam = ingredientFactory.createClam();//蛤蜊
    }
}

class PepperoniPizza extends Pizza{
    PizzaIngredientFactory ingredientFactory;
    public PepperoniPizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory = ingredientFactory;
    }
    void prepare(){
        System.out.println("Preparing" + name);
        dough = String.valueOf(ingredientFactory.createDough());//面包片
        sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
        cheese = ingredientFactory.createCheese();//芝士
    }
}

/**
* 纽约加盟店
**/
class NYPizzaStore extends PizzaStore{
    protected Pizza createPizza(String item){
        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
        if(item.equals("cheese")){
            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("New York Style Cheese Pizza");
        }else if(item.equals("veggie")){
            pizza = new VeggiePizza(ingredientFactory);
            pizza.setName("New York Style Veggie Pizza");
        }else if(item.equals("clam")){
            pizza = new ClamPizza(ingredientFactory);
            pizza.setName("New York Style Clam Pizza");
        }else if(item.equals("pepperoni")){
            pizza = new PepperoniPizza(ingredientFactory);
            pizza.setName("New York Style Pepperoni Pizza");
        }
        return pizza;
    }
}

/**
* 其他原料类
* */
class Sauce {
}
class Cheese {
}
class Veggies{
}
class Pepperoni {
}
class Clams {
}

/**
 * Pizza原料工厂接口
 * 每个原料类都有一个对应的方法创建该原料
 * */
interface PizzaIngredientFactory{
    public Dough createDough();
    public Sauce createSauce();
    public Cheese createCheese();
    public Veggies[] createVeggies();
    public Pepperoni createPepperoni();
    public Clams createClam();
}

输出

PreparingNew York Style Cheese Pizza
bake over!
cut over!
box over!
New York Style Cheese Pizza准备完毕!


在这里插入图片描述
这里的工厂使用了抽象类,用于创建相关或依赖对象的家族,而不需要明确指定具体类。使用对象组合。

抽象工厂模式定义了一个接口,所有的具体工厂都必须实现此接口,这个接口包含一组方法用来生产产品。每个具体的工厂都可以生产所有的产品。
在这里插入图片描述
看了上述的类图可以发现,与工厂模式不同的是,一旦需要扩展这组产品,就需要更改接口,相应的子类的接口也要改变。此外,抽象工厂模式中的具体工厂会使用到工厂模式。

三、总结与补充

1、将PizzaStore从简单工厂优化到工厂,从而优化(抽象)一个共性:地域风格,例如纽约风格,芝加哥风格,中式风格。
2、产品类Pizza和创建类PizzaStore都抽象化,并根据依赖倒置原则,将顶层PizzaStore和低层具体的Pizza类都设计为依赖产品类。形成抽象工厂(工厂模式之间的区别见5)。
3、原料类抽象化,然后将其子类实例作为pizza子类的参数(即采用构造器方式注入)。
4、总之,将共性抽象化,实现客户与实际对象创建的解耦。

3.1.什么时候使用工厂模式?

为了提高扩展性和维护性,多写些代码是值得的。
1、类本身有很多子类,并且经常会发生变化。创建对象需要大量重复的代码。比如肯德基新品。
2、消费者不关心如何创建对象(产品类)。

3.2.简单工厂模式和工厂模式有什么区别?

简单工厂模式是“一把抓”

//SimplePizzaFactory,创建披萨
public class SimplePizzaFactory{
    public Pizza createPizza(String type){
        Pizza pizza = null;
         //上述代码段
         if(type.equals("cheese")){//奶酪
            pizza = new CheesePizza("cheese");
         }else if(type.equals("greek")){//希腊
            pizza = new GreekPizza("greek");
         }else if(type.equals("pepperoni")){//香肠
             pizza = new PeppernoiPizza("pepperoni");
         }else.....
     //增加新的产品。。。
    }
}

1、负担太重
2、不符合开闭原则
● 工厂方法模式就很好的减轻了工厂类的负担,把某一类/某一种东西交由一个工厂生产;(对应简单工厂的缺点1)。
● 同时增加某一类 ”东西“ 并不需要修改工厂类,只需要添加生产这类 ”东西“ 的工厂即可,使得工厂类符合开放-封闭原则。

3.3.工厂模式是否遵守了开闭原则?

开闭原则: 对扩展开放,对修改关闭
(1)增加产品族:对于增加新的产品族,抽象工厂模式很好地支持了“开闭原则”,只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改。
(2)增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了“开闭原则”。

3.4.抽象工厂、工厂、简单工厂的区别

工厂与简单工厂: 简单工厂是工厂的一种特例,可以简单理解简单工厂就是一个超级工厂,包罗万象,产品之间无关联。而工厂就是把这个超级工厂给抽象化,并划分成多个子工厂。
抽象工厂: 抽象工厂的目的是减少工厂数量,但是具备一定的条件,即这些工厂需要具备至少两个及以上的共性。拿披萨为例,即可以分多个维度去分类,如地域、口味、原料三个维度。按照地域可以分为纽约、芝加哥等等。按照口味可以分为芝士、巧克力等等。按照原料可以分为葱、面包等等。将至少两个以上的这种共性抽象化,即抽象工厂。

四、参考文献

1.抽象工厂模式与开闭原则_iteye_7839的博客-CSDN博客
2.工厂模式和抽象工厂的区别是什么? - Single_Yam - 博客园 (cnblogs.com)

最后,设计模式的设计并没有完美的,一个项目的开发,也是结合各种模式的优缺点来设计,看到其优缺点灵活使用即可。
OVER~
在这里插入图片描述
我讲明白了吗?欢迎评论交流~
以上是对工厂模式学习过程的总结,如果对您有帮助,记得留个赞哦~

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂java杰尼龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值