设计模式之工厂模式

工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

基本介绍

定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

主要解决

主要解决接口选择的问题。

何时使用

我们明确地计划不同条件下创建不同实例时。

如何解决

让其子类实现工厂接口,返回的也是一个抽象的产品。

关键代码

创建过程在其子类执行。

应用实例

  • 需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现;
  • Hibernate 换数据库只需换方言和驱动就可以

优点

  • 一个调用者想创建一个对象,只要知道其名称就可以了;
  • 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
  • 屏蔽产品的具体实现,调用者只关心产品的接口。

缺点

每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

注意事项

作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

项目需求

看一个披萨项目,需便于披萨种类的扩展,便于维护。

  1. 披萨的种类很多:(GreeKPizzCheesePizz等);
  2. 披萨的制作有:prepare(准备材料)、bake(制作)、cut(切割)、box(打包);
  3. 完成披萨店订购功能。

分析

在这里插入图片描述

代码实现

public abstract class Pizza {
	private String name;

	public Pizza(String name){
		this.name = name;
	}

	/**
	 * 由于不同类型的披萨需要的原材料不同,我们把准备原材料的方法制作为抽象方法
	 */
	public abstract void prepare();

	/**
	 * 制作披萨
	 */
	public void bake(){
		System.out.println("完成 " + name + " 的披萨制作");
	}

	/**
	 * 披萨切割
	 */
	public void cut(){
		System.out.println("完成 " + name + " 的披萨切割");
	}

	/**
	 * 披萨切割
	 */
	public void box(){
		System.out.println("完成 " + name + " 的披萨打包");
	}
}

public class CheesePizza extends Pizza {
	public CheesePizza() {
		super("奶酪披萨");
	}

	@Override
	public void prepare() {
		System.out.println("完成 奶酪披萨 原材料准备");
	}
}

public class GreekPizza extends Pizza{

	public GreekPizza() {
		super("希腊披萨");
	}

	@Override
	public void prepare() {
		System.out.println("完成希腊披萨原材料准备");
	}
}

public class OrderPizza {

	public OrderPizza(){
		Pizza pizza = null;
		String orderType;
		orderType = getName();
		if ("greek".equals(orderType)){
			pizza = new GreekPizza();
		}else if ("cheese".equals(orderType)){
			pizza = new CheesePizza();
		}
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();
	}

	private String getName(){
		String name = null;
		try(BufferedReader inputStream = new BufferedReader(new InputStreamReader(System.in))){
			System.out.println(" input pizza Type");
			name = inputStream.readLine();
		}catch (IOException exception){exception.printStackTrace();}
		return name;
	}
}

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

当出现一种新的披萨种类时就需要我们去修改代码,需要添加一种Pizza,然后去修改OrderPizza类,当OrderPizza有很多的时候修改的代码量就会有很多。

分析:修改代码可以接受,但是如果我们在其他的地方也有创建Pizza的代码就意味着也需要修改,而创建Pizza的代码往往有很多出。

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

简单工厂模式

基本介绍

在这里插入图片描述

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

代码实现

public abstract class Pizza {
	private String name;

	public Pizza(String name){
		this.name = name;
	}

	/**
	 * 由于不同类型的披萨需要的原材料不同,我们把准备原材料的方法制作为抽象方法
	 */
	public abstract void prepare();

	/**
	 * 制作披萨
	 */
	public void bake(){
		System.out.println("完成 " + name + " 的披萨制作");
	}

	/**
	 * 披萨切割
	 */
	public void cut(){
		System.out.println("完成 " + name + " 的披萨切割");
	}

	/**
	 * 披萨切割
	 */
	public void box(){
		System.out.println("完成 " + name + " 的披萨打包");
	}
}

public class CheesePizza extends Pizza {
	public CheesePizza() {
		super("奶酪披萨");
	}

	@Override
	public void prepare() {
		System.out.println("完成 奶酪披萨 原材料准备");
	}
}

public class GreekPizza extends Pizza{

	public GreekPizza() {
		super("希腊披萨");
	}

	@Override
	public void prepare() {
		System.out.println("完成希腊披萨原材料准备");
	}
}

public class SimpleFactroy {

	public Pizza createPizza(String orderType){
		System.out.println("使用简单工厂模式");
		Pizza pizza = null;
		if ("greek".equals(orderType)){
			pizza = new GreekPizza();
		}else if ("cheese".equals(orderType)){
			pizza = new CheesePizza();
		}
		return pizza;
	}

	//简单工厂模式也叫做静态工厂模式,一般选择一下形式
	public static Pizza createPizza1(String orderType){
		System.out.println("使用简单工厂模式1");
		Pizza pizza = null;
		if ("greek".equals(orderType)){
			pizza = new GreekPizza();
		}else if ("cheese".equals(orderType)){
			pizza = new CheesePizza();
		}
		return pizza;
	}
}

public class OrderPizza {
    public OrderPizza(SimpleFactroy simpleFactroy){
        setSimpleFactroy(simpleFactroy);
    }

	private SimpleFactroy simpleFactroy;

	public void setSimpleFactroy(SimpleFactroy simpleFactroy) {
		this.simpleFactroy = simpleFactroy;
		Pizza pizza = simpleFactroy.createPizza(getName());
		do{
			if ( pizza != null){
				pizza.prepare();
				pizza.bake();
				pizza.cut();
				pizza.box();
			}else{
				break;
			}
		}while (true);
	}

	private String getName(){
		String name = null;
		try{
			BufferedReader inputStream = new BufferedReader(new InputStreamReader(System.in));
			System.out.println(" input pizza Type");
			name = inputStream.readLine();
		}catch (IOException exception){exception.printStackTrace();}
		return name;
	}
}

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

工厂方法模式

模拟需求

披萨项目:在客户在点披萨是,可以点不同口味的披萨,比如北京的奶酪披萨、北京的胡椒披萨、伦敦的奶酪披萨、伦敦的胡椒披萨;

分析

使用简单工厂模式,创建不同的简单工厂,比如北京披萨工厂、伦敦披萨工厂等,但是考虑到软件的可维护行、可扩展性并不是很好;

基本介绍

在这里插入图片描述

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

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

代码实现


public class BJCheesePizza extends Pizza {
   public BJCheesePizza() {
      super("北京奶酪披萨");
   }

   @Override
   public void prepare() {
      System.out.println("完成 北京奶酪披萨 原材料准备");
   }
}

public class BJGreekPizza extends Pizza {

	public BJGreekPizza() {
		super("北京希腊披萨");
	}

	@Override
	public void prepare() {
		System.out.println("完成北京希腊披萨原材料准备");
	}
}

public class BjOrderPiazza extends OrderPiazza{
	@Override
	public Pizza createPizza(String orderType) {
		Pizza pizza = null;
		if ("greek".equals(orderType)){
			pizza = new BJGreekPizza();
		}else if ("cheese".equals(orderType)){
			pizza = new BJCheesePizza();
		}
		return pizza;
	}
}


public class LDCheesePizza extends Pizza {
	public LDCheesePizza() {
		super("伦敦奶酪披萨");
	}

	@Override
	public void prepare() {
		System.out.println("完成 伦敦奶酪披萨 原材料准备");
	}
}

public class LDGreekPizza extends Pizza {

	public LDGreekPizza() {
		super("伦敦希腊披萨");
	}

	@Override
	public void prepare() {
		System.out.println("完成 伦敦希腊披 萨原材料准备");
	}
}

public class LDOrderPiazza extends OrderPiazza{

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

public abstract class OrderPiazza {

	public abstract Pizza createPizza(String orderType);
	
	public void getPizza(){
		do{
			Pizza pizza = createPizza(getName());
			if ( pizza != null){
				pizza.prepare();
				pizza.bake();
				pizza.cut();
				pizza.box();
			}else{
				break;
			}
		}while (true);
	}

	private String getName(){
		String name = null;
		try{
			BufferedReader inputStream = new BufferedReader(new InputStreamReader(System.in));
			System.out.println(" input pizza Type");
			name = inputStream.readLine();
		}catch (IOException exception){exception.printStackTrace();}
		return name;
	}
}


public abstract class Pizza {
	private String name;

	public Pizza(String name){
		this.name = name;
	}

	/**
	 * 由于不同类型的披萨需要的原材料不同,我们把准备原材料的方法制作为抽象方法
	 */
	public abstract void prepare();

	/**
	 * 制作披萨
	 */
	public void bake(){
		System.out.println("完成 " + name + " 的披萨制作");
	}

	/**
	 * 披萨切割
	 */
	public void cut(){
		System.out.println("完成 " + name + " 的披萨切割");
	}

	/**
	 * 披萨切割
	 */
	public void box(){
		System.out.println("完成 " + name + " 的披萨打包");
	}
}


public class TestPizza {
	public static void main(String[] args) {
		OrderPiazza piazza = new LDOrderPiazza();
		piazza.getPizza();
	}
}

抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

基本介绍

  • 抽象工厂模式:定义了一个接口用于创建相关或有依赖关系的对象簇,而无需指明具体的类;
  • 抽象工程模式可以看出将简单工厂模式工厂方法模式进行整合;
  • 在设计层面看,抽象工厂模式就是对简单工厂模式的改进或者称为进一步的抽象
  • 将工厂抽象成两层,ABSFactory抽象工厂和具体实现的工厂子类。我们可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。

在这里插入图片描述

主要解决

主要解决接口选择的问题。

何时使用

系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。

如何解决

在一个产品族里面,定义多个产品。

关键代码

在一个工厂里聚合多个同类产品。

应用实例

工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况(现实中是不存在的,要不然,没法进入共产主义了,但有利于说明抽象工厂模式),在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 OOP 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。

优点

当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点

产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。

代码实现

public interface ABSFactory {
	Pizza createPizza(String orderType);
}

public class BJCheesePizza extends Pizza {
	public BJCheesePizza() {
		super("北京奶酪披萨");
	}

	@Override
	public void prepare() {
		System.out.println("完成 北京奶酪披萨 原材料准备");
	}
}

public class BJFactory implements ABSFactory {

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

public class BJGreekPizza extends Pizza {

	public BJGreekPizza() {
		super("北京希腊披萨");
	}

	@Override
	public void prepare() {
		System.out.println("完成北京希腊披萨原材料准备");
	}
}

public class LDCheesePizza extends Pizza {
	public LDCheesePizza() {
		super("伦敦奶酪披萨");
	}

	@Override
	public void prepare() {
		System.out.println("完成 伦敦奶酪披萨 原材料准备");
	}
}

public class LDFcatory implements ABSFactory {
	@Override
	public Pizza createPizza(String orderType) {
		Pizza pizza = null;
		if ("greek".equals(orderType)){
			pizza = new LDGreekPizza();
		}else if ("cheese".equals(orderType)){
			pizza = new LDCheesePizza();
		}
		return pizza;
	}
}

public class LDGreekPizza extends Pizza {

	public LDGreekPizza() {
		super("伦敦希腊披萨");
	}

	@Override
	public void prepare() {
		System.out.println("完成 伦敦希腊披 萨原材料准备");
	}
}

public class OrderPiazza {

	private ABSFactory factory;

	private void setFactory(ABSFactory factory) {
		this.factory = factory;
	}

	public OrderPiazza(ABSFactory factory){
		setFactory(factory);
	}

	public void getPizza(){
		do{
			Pizza pizza = factory.createPizza(getName());
			if ( pizza != null){
				pizza.prepare();
				pizza.bake();
				pizza.cut();
				pizza.box();
			}else{
				break;
			}
		}while (true);
	}

	private String getName(){
		String name = null;
		try{
			BufferedReader inputStream = new BufferedReader(new InputStreamReader(System.in));
			System.out.println(" input pizza Type");
			name = inputStream.readLine();
		}catch (IOException exception){exception.printStackTrace();}
		return name;
	}
}

public abstract class Pizza {
	private String name;

	public Pizza(String name){
		this.name = name;
	}

	/**
	 * 由于不同类型的披萨需要的原材料不同,我们把准备原材料的方法制作为抽象方法
	 */
	public abstract void prepare();

	/**
	 * 制作披萨
	 */
	public void bake(){
		System.out.println("完成 " + name + " 的披萨制作");
	}

	/**
	 * 披萨切割
	 */
	public void cut(){
		System.out.println("完成 " + name + " 的披萨切割");
	}

	/**
	 * 披萨切割
	 */
	public void box(){
		System.out.println("完成 " + name + " 的披萨打包");
	}
}

public class TestPizza {
	public static void main(String[] args) {
		new OrderPiazza(new BJFactory()).getPizza();
	}
}

源码分析

JDK

JDL中的Calendar类中就使用了简单工厂模式;

在这里插入图片描述

根据不同的类型会创建不同的对象;

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

小结

  • 工厂模式的意义:将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系进行解耦,从而提高项目的可扩展性和维护性;
  • 三种工厂模式(简单工厂模式工厂方法模式抽象工厂模式);
  • 创建对象实例时,不要直接new 类,而是吧这个new 类的动作放到一个工厂的方法中并返回,变量不要直接持有具体类的引用
  • 不要让类集成具体类,而是集成抽象类或者实现接口;
  • 披萨切割
    */
    public void box(){
    System.out.println(“完成 " + name + " 的披萨打包”);
    }
    }

public class TestPizza {
public static void main(String[] args) {
new OrderPiazza(new BJFactory()).getPizza();
}
}


# 源码分析

## JDK

JDL中的`Calendar`类中就使用了简单工厂模式;

[外链图片转存中...(img-e3bhzbVU-1712566022861)]

根据不同的类型会创建不同的对象;

[外链图片转存中...(img-eOKFjAt6-1712566022861)]

[外链图片转存中...(img-v4hp4WKY-1712566022861)]

[外链图片转存中...(img-T7IJVwVU-1712566022861)]

## 小结

- 工厂模式的意义:将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系进行解耦,从而提高项目的可扩展性和维护性;
- 三种工厂模式(`简单工厂模式`、`工厂方法模式`、`抽象工厂模式`);
- 创建对象实例时,不要直接`new 类`,而是吧这个`new 类`的动作放到一个工厂的方法中并返回,**变量不要直接持有具体类的引用**;
- 不要让类集成具体类,而是集成抽象类或者实现接口;
- 不要覆盖基类中已经实现的方法。
  • 28
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值