Head First Design Patterns -工厂模式

什么是工厂模式

工厂方法模式定义了一个创建对象的接口,但由子类来决定要实例化那个类。工厂方法让类把实例化推迟到了子类。

为什么要有工厂模式

书中以pizza店制作pizza为例子,假设不用工厂模式,在制作pizza阶段我们需要这样去实例化类:

java 复制代码
Pizza orderPizza(String type) {
	Pizza pizza;
	
	// 基于pizza的类型,实例化具体的类,这里的每个pizza都需要实现Pizza接口
	if (type.equals("cheess")) {
		pizza = new CheesePizza();
	} else if (type.equals("greek")) {
		pizza = new GreekPizza();
	}

	// pizza的前期准备
	pizza.prepare();
	pizza.bake();
	return pizza;
}

上述代码不符合开闭原则,一旦pizza店改变pizza的供应,则需要修改上述代码

简单工厂模式

简单工厂模式并不是一种设计模式,而是一种编程习惯,定义一个工厂类,这个类封装所有披萨的对象创建,pizza店客户端中不会进行实例化

代码如下:

java 复制代码
// 简单工厂代码
public Pizza SimplePizzaFactory {
	public Pizza createPizza(String type) {
		Pizza pizza = null;
		if (type.equals("cheess")) {
			pizza = new CheesePizza();
		} else if (type.equals("greek")) {
			pizza = new GreekPizza();
		}
	}
}

// pizza店客户端代码
public class PizzaStore {
	SimplePizzaFactory factory;
	
	public PizzaStore(SimplePizzaFactory factory) {
		this.factory = factory;
	}

	public Pizza orderPizza(String type) {
		Pizza pizza;
		pizza = factory.createPizza(type);
		// pizza的前期准备
		pizza.prepare();
		pizza.bake();
		return pizza;
	}
}

简单工厂模式的类图:

简单工厂模式的优点:

  • 将变化的部分抽离出来独立形成工厂,避免在客户端直接创建

简单工厂模式的缺点:

  • 简单工厂只是提供了封装对象创建的一种方式,但没有提供工厂方法的弹性,因为它没有办法改变正在创建的产品。

工厂模式

如果pizza店引入了加盟商,加盟商对于pizza需要有一些自己的定制化需求,而上面的简单工厂模式,则不符合这种需求,需要引入工厂模式。

具体代码:

1、定义pizza店接口

java 复制代码
public 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); // 交给子类进行实例化
}

2、 抽象pizza的制作流程

java 复制代码
public abstract class Pizza {
    String name;
    String dough;

    void prepare() {
        System.out.println("prepare finish");
    };
    void bake() {
        System.out.println("bake finish");
    };

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

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

    public String getName() {return name;};
}

3、定义加盟商的定制化需求

java 复制代码
public class NYPizzaStore extends PizzaStore{

    @Override
    public Pizza createPizza(String item) {
        if (item.equals("cheese")) {
            return new NYStyleCheesePizza();
        }else return null;
    }
}

4、定义加盟商所使用的pizza材料

java 复制代码
public class NYStyleCheesePizza extends Pizza{
    public NYStyleCheesePizza() {
        String name = "NY Style pizza";
        String dough = "thin crust dough";
        String sauce = "Marinara Sauce";
    }
}

5、main函数执行

java 复制代码
public class Main {
    public static void main(String[] args) {
        PizzaStore nyStore = new NYPizzaStore();

        Pizza pizza = nyStore.orderPizza("cheese");

    }

}

执行结果:

prepare finish

bake finish

cut finish

box finish

工厂模式的类图:

工厂模式中引入的设计原则:

  • 依赖倒置原则:依赖抽象,而不应该依赖具体类

遵循依赖倒置设计原则的指南:

  • 变量不应该持有到具体类的引用
  • 类不应该派生自具体类
  • 方法不应该覆盖任何基类的已实现方法
    (以上指南并不是铁律,要看具体的场景来遵守)

抽象工厂模式

抽象工厂模式提供一个接口来创建相关或依赖对象的家族,而并不需要指定具体的类

比较工厂方法与抽象工厂方法:

工厂方法:

抽象工厂方法:

区别:

  • 工厂方法中只会提供一个抽象接口,接口的实现交给各个工厂去做,抽象类只会知道是制作一个pizza。
  • 抽象工厂是把工厂方法中的接口给拆开了,提供抽象接口的组合。会感知到制作pizza的抽象信息。
  • 抽象方法中对于每一个抽象接口的实现,利用了工厂方法的思路。
相关推荐
重生之后端学习25 分钟前
02-前端Web开发(JS+Vue+Ajax)
java·开发语言·前端·javascript·vue.js
字节源流6 小时前
关于maven的依赖下不下来的问题
java·maven
pjx9877 小时前
服务间的“握手”:OpenFeign声明式调用与客户端负载均衡
java·运维·spring·负载均衡
prinrf('千寻)7 小时前
MyBatis-Plus 的 updateById 方法不更新 null 值属性的问题
java·开发语言·mybatis
老华带你飞8 小时前
实习记录小程序|基于SSM+Vue的实习记录小程序设计与实现(源码+数据库+文档)
java·数据库·spring boot·小程序·论文·毕设·实习记录小程序
在未来等你8 小时前
互联网大厂Java求职面试:AI与大模型应用集成及云原生挑战
java·微服务·ai·kubernetes·大模型·embedding·spring ai
源码技术栈8 小时前
SaaS基于云计算、大数据的Java云HIS平台信息化系统源码
java·大数据·云计算·云his·his系统·云医院·区域his
编程、小哥哥8 小时前
互联网大厂Java面试:从Spring Boot到微服务架构的技术深挖
java·spring boot·redis·微服务·prometheus·面试技巧
揽你·入怀9 小时前
数据结构:ArrayList简单实现与常见操作实例详解
java·开发语言
okok__TXF9 小时前
SpringBoot3+AI
java·人工智能·spring