工厂模式(由浅到深学习设计模式)

工厂模式


  1. 概述

将创建对象new的动作,进行工厂模式的封装调用,达到项目层次依赖关系的解耦,也就是“变量不要直接持有具体类的引用”。

  1. 应用场景(何时使用)

对象各种需求过多时可用到工厂模式,达到依赖的解耦
1、披萨订购系统,披萨种类包含:伦敦胡椒披萨、伦敦奶酪披萨、北京胡椒披萨、北京奶酪披萨(四种披萨类型,以后还将扩展)
2、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现

  1. 三种方式(简单工厂、工厂方法、抽象工厂)
以下均用 披萨订购系统 举例说明:
1、简单工厂
步骤如下:
1)	Pizza抽象类,包括披萨名称制作流程,让其子类实现
2)	写一个简单工厂,维护不同的披萨类型
3)	订购披萨,套用简单工厂的动态下订单
4)	代码实现

在这里插入图片描述
Pizza类

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
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 void setName(String name) {
		this.name = name;
	}
}

CheesePizza实现类(其他实现大同小异)

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
public class CheesePizza extends Pizza {

	@Override
	public void prepare() {
		// TODO Auto-generated method stub
		System.out.println(" 给制作奶酪披萨 准备原材料 ");
	}

}

在这里插入图片描述
SimpleFactory类(工厂,重点代码)

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
//简单工厂类
public class SimpleFactory {

	//更加orderType 返回对应的Pizza 对象
	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类(披萨订单)

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
public class OrderPizza {

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

	//构造器
	public OrderPizza(SimpleFactory simpleFactory) {
		setFactory(simpleFactory);
	}

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

		this.simpleFactory = simpleFactory; //设置简单工厂对象

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

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

	// 写一个方法,可以获取客户希望订购的披萨种类
	private String getType() {
		try {
			BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
			System.out.println("input pizza 种类:");
			String str = strin.readLine();
			return str;
		} catch (IOException e) {
			e.printStackTrace();
			return "";
		}
	}

}

客户端调用

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
public class PizzaStore {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		//使用简单工厂模式
		new OrderPizza(new SimpleFactory());
		System.out.println("~~退出程序~~");

	}

}
优缺点说明:
在单维度(胡椒披萨、奶酪披萨...)加工使用时可以使用简单工厂模式,但是在多维度(北京胡椒披萨、南京奶酪
披萨...)使用时,则不适用简单工厂。
2、工厂方法

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

步骤如下:
1)	Pizza抽象类,包括披萨名称制作流程,让其子类实现(新增地域维度,如北京xx披萨...)
2)	写一个或多个工厂方法,继承父类,根据地域来维护披萨类型
3)	订购披萨,让工厂方法去继承订购
4)	代码实现

在这里插入图片描述

Pizza类

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
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 void setName(String name) {
		this.name = name;
	}
}

BJCheesePizza实现类(其他实现大同小异)

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
public class BJCheesePizza extends Pizza {

	@Override
	public void prepare() {
		// TODO Auto-generated method stub
		setName("北京的奶酪pizza");
		System.out.println(" 北京的奶酪pizza 准备原材料");
	}

}

在这里插入图片描述

BJOrderPizza类(工厂方法,继承OrderPizza,重点代码)

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
public class BJOrderPizza extends OrderPizza {


	@Override
	Pizza createPizza(String orderType) {

		Pizza pizza = null;
		if(orderType.equals("cheese")) {
			pizza = new BJCheesePizza();
		} else if (orderType.equals("pepper")) {
			pizza = new BJPepperPizza();
		}
		// TODO Auto-generated method stub
		return pizza;
	}

}

OrderPizza类(披萨订单)

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
public abstract class OrderPizza {

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

	// 构造器
	public OrderPizza() {
		Pizza pizza = null;
		String orderType; // 订购披萨的类型
		do {
			orderType = getType();
			pizza = createPizza(orderType); //抽象方法,由工厂子类完成
			//输出pizza 制作过程
			pizza.prepare();
			pizza.bake();
			pizza.cut();
			pizza.box();

		} while (true);
	}



	// 写一个方法,可以获取客户希望订购的披萨种类
	private String getType() {
		try {
			BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
			System.out.println("input pizza 种类:");
			String str = strin.readLine();
			return str;
		} catch (IOException e) {
			e.printStackTrace();
			return "";
		}
	}

}

客户端调用(以北京为例)

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
public class PizzaStore {

	public static void main(String[] args) {
		String loc = "bj";
		if (loc.equals("bj")) {
			//创建北京口味的各种Pizza
			new BJOrderPizza();
		} else {
			//创建伦敦口味的各种Pizza
			new LDOrderPizza();
		}
	}

}
优缺点说明:
工厂方法采用继承,能够提供一种框架,约束子类。但是容易产生类爆炸问题。
3、抽象工厂

需求还是和工厂方法一样,只是代码写法改变

步骤如下:
1)	Pizza抽象类,包括披萨名称制作流程,让其子类实现(新增地域维度,如北京xx披萨...)
2)	写一个抽象工厂,让一个或多个子类实现工厂
3)	订购披萨,引入抽象工厂
4)	代码实现

在这里插入图片描述

Pizza类

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
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 void setName(String name) {
		this.name = name;
	}
}

BJCheesePizza实现类(其他实现大同小异)

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
public class BJCheesePizza extends Pizza {

	@Override
	public void prepare() {
		// TODO Auto-generated method stub
		setName("北京的奶酪pizza");
		System.out.println(" 北京的奶酪pizza 准备原材料");
	}

}

在这里插入图片描述

AbsFactory类(抽象工厂模式的抽象层)

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
public interface AbsFactory {
	//让下面的工厂子类来 具体实现
	public Pizza createPizza(String orderType);
}

BJFactory类(工厂子类,实现抽象工厂)

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
public class BJFactory implements AbsFactory {

	@Override
	public Pizza createPizza(String orderType) {
		System.out.println("~使用的是抽象工厂模式~");
		// TODO Auto-generated method stub
		Pizza pizza = null;
		if(orderType.equals("cheese")) {
			pizza = new BJCheesePizza();
		} else if (orderType.equals("pepper")){
			pizza = new BJPepperPizza();
		}
		return pizza;
	}

}

OrderPizza类

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
public class OrderPizza {

	AbsFactory factory;

	// 构造器
	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 (pizza != null) { // 订购ok
				pizza.prepare();
				pizza.bake();
				pizza.cut();
				pizza.box();
			} else {
				System.out.println("订购失败");
				break;
			}
		} while (true);
	}

	// 写一个方法,可以获取客户希望订购的披萨种类
	private String getType() {
		try {
			BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
			System.out.println("input pizza 种类:");
			String str = strin.readLine();
			return str;
		} catch (IOException e) {
			e.printStackTrace();
			return "";
		}
	}
}

客户端调用(以伦敦为例)

/**
 * @author 漆剑
 * @date 2021-03-27
 * @description
 */
public class PizzaStore {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//new OrderPizza(new BJFactory());
		new OrderPizza(new LDFactory());
	}

}
优缺点说明:
1)抽象工厂,采用组合,抽象层级在工厂方法之上,所以抽象工厂里其实经常使用到工厂方法的思想。
2)将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的
工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
  1. 总结

1、一个调用者想创建一个对象,只要知道其名称就可以了
2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以
3、屏蔽产品的具体实现,调用者只关心产品的接口
4、每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度

由于水平有限,本博客难免有不足,恳请各位大佬不吝赐教!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值