设计模式学习(二)工厂模式

129 阅读7分钟

这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战 @TOC

简单工厂模式

传统方式

  1. 通过一个传统的项目来介绍工厂模式:看一个包子的项目:要便于包子种类的扩展,要便于维护,需求如下:
    • 包子的种类很多 比如肉包子,菜包子等
    • 包子的制作有 prepare,baopi, fangruxianliao, cooking
    • 完成包子店订购功能。
  2. 代码如下:
  • 包子铺
public class baoziStore {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		new OrderBaozi();
	}

}

  • 购买包子
public class OrderBaozi {
	
	//构造器
	public OrderBaozi() {
		baozi b = null;
		String baozistyle;
		do {
			baozistyle = getType();
			if(baozistyle.equals("肉包子")) {
				b = new roubaozi();
			}else if(baozistyle.equals("菜包子")) {
				b = new caibaozi();
			}else {
				break;
			}
			b.prepare();
			b.baopi();
			b.baoxian();
			b.cooking();
		}while(true);
	}
	
	// 写一个方法,可以获取客户希望订购的包子种类
	private String getType() {
		try {
			BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
			System.out.println("input 包子 种类:");
			String str = strin.readLine();
			return str;
		} catch (IOException e) {
			e.printStackTrace();
			return "";
		}
	}

}
  • 包子抽象类
public abstract class baozi {
	protected String name;
	public abstract void prepare();
	public void baopi() {
		System.out.println(name + " 正在准备包皮;");
	}
	public void baoxian() {
		System.out.println(name + " 正在准备包馅;");
	}
	public void cooking() {
		System.out.println(name + " 正在蒸包子;");
	}
	public void setName(String name) {
		this.name = name;
	}
}
  • 肉包子
public class roubaozi extends baozi{

	@Override
	public void prepare() {
		setName("肉包子");
		System.out.println(name + "正在准备!");
		
	}

}
  • 菜包子
public class caibaozi extends baozi{

	@Override
	public void prepare() {
		setName("菜包子");
		System.out.println(name+"正在准备!!");
		
	}
	

}
  • 结果: 在这里插入图片描述
  1. 结论:
    • 优点是比较好理解,简单易操作。
    • 缺点是违反了 设 计模式的 ocp 原则,即 对扩展开放,对修改关闭 。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码

改进传统方式:简单工厂模式

  1. 改进思路:把 创建包子对象封装到一个类中,这样我们有新的包子种类时,只需要修改该类就可, 其它有创建 到 包子对象的代码就不需要修改了
  2. 代码改进:
  • 创建一个singleFactory对象用于创建包子
public class SingleFactory {
	public baozi createBaozi(String type) {
		baozi b = null;
		if(type.equals("肉包子")) {
			b = new roubaozi();
		}else if(type.equals("菜包子")) {
			b = new caibaozi();
		}
		return b;
	}

}
  • 修改OrderBaozi,使用简单工厂创建包子
public class OrderBaozi {
	//简单工厂模式
	SingleFactory singleFactory;
	baozi b = null;
	
	//订购包子构造器
	public OrderBaozi(SingleFactory singleFactory) {
		setFactory(singleFactory);
	}
	
	public void setFactory(SingleFactory singleFactory) {
		String type = "";
		this.singleFactory = singleFactory;
		do {		
			type = getType();
			b = this.singleFactory.createBaozi(type);
			
			//输出包子
			if(b!=null) {
				b.prepare();
				b.baopi();
				b.baoxian();
				b.cooking();
			}else {
				System.out.println("订购失败");
				break;
			}
		}while(true);
		
		
	}
	
	// 写一个方法,可以获取客户希望订购的包子种类
	private String getType() {
		try {
			BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
			System.out.println("input 包子 种类:");
			String str = strin.readLine();
			return str;
		} catch (IOException e) {
			e.printStackTrace();
			return "";
		}
	}

}
  • 修改main方法
public class baoziStore {

	public static void main(String[] args) {
		//传统方式
//		new OrderBaozi();
		
		//简单工厂模式
		new OrderBaozi(new SingleFactory());
	}

}

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

工厂模式

  1. 工厂方法模式介绍
    • 工厂方法模式设计方案:将包子项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。
    • 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将 对象的实例化推迟到子类 。
  2. 实例演示:
  • 需求:包子项目新的需求:客户在点包子时,可以根据不同地点,点不同口味的包子,比如深圳肉包子,北京肉包子
  1. 代码演示:
  • 包子抽象类
public abstract class BaoZi {
	protected String name;
	public abstract void prepare();
	public void baopi() {
		System.out.println(name + " 正在准备包皮;");
	}
	public void baoxian() {
		System.out.println(name + " 正在准备包馅;");
	}
	public void cooking() {
		System.out.println(name + " 正在蒸包子;");
	}
	public void setName(String name) {
		this.name = name;
	}

}
  • 深圳肉包子,深圳菜包子:
public class SzRouBaozi extends BaoZi{

	@Override
	public void prepare() {
		setName("深圳肉包子");
		System.out.println(name+"正在准备了");
		
	}
	
	

}
public class SzCaiBaoZi extends BaoZi{

	@Override
	public void prepare() {
		setName("深圳菜包子");
		System.out.println(name+"正在准备了");
	}

}
  • 北京菜包子,北京菜包子:

public class BjRouBaoZi extends BaoZi{

	@Override
	public void prepare() {
		setName("北京肉包子");
		System.out.println(name+"正在准备了");
		
	}
	

}
public class BjCaiBaoZi extends BaoZi{

	@Override
	public void prepare() {
		setName("北京菜包子");
		System.out.println(name+"正在准备了");
		
	}
	

}


  • 包子工厂抽象类
public abstract class OrderBaoZi {
	
	//定义一个抽象方法,createBaozi , 让各个工厂子类自己实现
	abstract BaoZi createBaozi(String type);
	
	//构造器
	public OrderBaoZi() {
		BaoZi b=null;
		String type = null;
		do {
			type = getType();
			b = createBaozi(type);
			b.prepare();
			b.baopi();
			b.baoxian();
			b.cooking();
		}while(true);
	}
	
	// 写一个方法,可以获取客户希望订购的披萨种类
	private String getType() {
		try {
			BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
			System.out.println("input 包子 种类:");
			String str = strin.readLine();
			return str;
		} catch (IOException e) {
			e.printStackTrace();
			return "";
		}
	}
	

}
  • 深圳包子工厂
public class SzOrderBaoZi extends OrderBaoZi{

	@Override
	BaoZi createBaozi(String type) {
		BaoZi b = null;
		if(type.equals("深圳肉包子")) {
			b = new SzRouBaozi();
		}else if(type.equals("深圳菜包子")){
			b = new SzCaiBaoZi();
		}
		return b;
	}

}
  • 北京包子工厂
public class BjOrderBaoZi extends OrderBaoZi{

	@Override
	BaoZi createBaozi(String type) {
		BaoZi b = null;
		if(type.equals("北京肉包子")) {
			b = new BjRouBaoZi();
		}else if(type.equals("北京菜包子")){
			b = new BjCaiBaoZi();
		}
		return b;
	}
	

}
  • 包子铺
public class BaoZiStore {

	public static void main(String[] args) {
		System.out.println("请问你身在哪里:深圳,北京");
		Scanner sc = new Scanner(System.in);
		String in = sc.nextLine();
		if(in.equals("深圳")) {
			System.out.println("欢迎来到深圳!!");
			new SzOrderBaoZi();
		}else if(in.equals("北京")){
			System.out.println("欢迎来到北京!!");
			new BjOrderBaoZi();
		}
		


	}

}
  • 结果: 在这里插入图片描述

抽象工厂模式

  1. 基本介绍:
    • 抽象工厂模式:定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类
    • 抽象工厂模式可以将 简单工厂模式 和 工厂方法模式进行整合。
    • 从设计层面看,抽象工厂模式就是对简单工厂模式的改进 或者称为进一步的抽象 。
    • 将工厂抽象成两层, AbsFactory( 抽象工厂 ) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。 这样将单个的简单工厂类变成了 工厂簇更利于代码的维护和扩展。
  2. 实例介绍:订pizza 在这里插入图片描述
  3. 代码
  • 抽象工厂AbsFactory
//一个抽象工厂模式的抽象层(接口)
public interface AbsFactory {
	//让下面的工厂子类来 具体实现
	public Pizza createPizza(String orderType);
}
  • BjFactory
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;
	}

}

  • LDFactory
public class LDFactory implements AbsFactory {

	@Override
	public Pizza createPizza(String orderType) {
		System.out.println("~使用的是抽象工厂模式~");
		Pizza pizza = null;
		if (orderType.equals("cheese")) {
			pizza = new LDCheesePizza();
		} else if (orderType.equals("pepper")) {
			pizza = new LDPepperPizza();
		}
		return pizza;
	}

}
  • OrderPizza
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 "";
		}
	}
}

工厂模式小结

  1. 工厂模式的意义

    • 将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
    • 三种工厂模式 简单工厂模式、工厂方法模式、抽象工厂模式
    • 设 计模式的 依赖 抽象 原则
  2. 细节:

    • 创 建对象实例时,不要直接 new 类 , 而是把这个 new 类的动作放在一个工厂的方法中,并返回。有的书上说,变量不要直接持有具体类的引用。
    • 不 要让类继承具体类,而是继承抽象类或者是 实 现 interface( 接口
    • 不 要覆盖基类中已经实现的方法。