简单工厂模式——不属于GOF23种设计模式之一却简单常用的一种设计模式

本文介绍了简单工厂模式的概念、结构和角色,通过披萨订购系统的例子展示了其实现过程。简单工厂模式允许创建一系列相关或相互依赖的对象,而无需指定它们的具体类。文章讨论了模式的优缺点,指出其在扩展性上的局限性,并通过引入简单工厂类解决了这一问题。最后,文章探讨了模式在实际应用中的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3 简单工厂模式 (Simple Factory Pattern)

3.1 动机与定义

  它不属于设计模式之一,但是非常简单常用,因此在此处介绍。

  简单工厂模式:又称为静态工厂方法(Static Factory Method)模式,属于创建型模式。==简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。==它定义了一个创建对象的类,由这个类来封装实例化对象行为

3.2 结构与角色

  简单工厂模式的实质由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类的实例,这些产品类继承自一个父类或接口。

  简单工厂模式包含三个角色。

①Factory:工厂。简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。

②Product:抽象产品。简单工厂模式所创建的所有对象的父类型,他负责描述所有实例所共用的接口。

③Concrete Product:具体产品。简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。

3.3 实例分析

  这里有一个披萨店,店里有两种披萨种类:GreekPizza、CheesePizza。披萨经过制作以后,你作为前台需要完成披萨店的订购功能。当有客人进行点单的时候,你需要确认订单通知制作披萨。接下来我们将用代码去一步步实现。

  首先是Product抽象产品的构建:

package SimpleFactoryPattern.PizzaStore.pizza;

//将Pizza类做成抽象
public abstract class Pizza {
	//披萨名字
	private 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;
	}
	
}

  Concrete Product:具体产品。我们的两种披萨,继承披萨父类,并实现prepare方法。

package SimpleFactoryPattern.PizzaStore.pizza;

public class CheesePizza extends Pizza{

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

}

package SimpleFactoryPattern.PizzaStore.pizza;

public class GreekPizza extends Pizza{

	@Override
	public void prepare() {
		// TODO Auto-generated method stub
		System.out.println("希腊披萨材料准备好了!");
	}

}

接下来就是订购披萨的操作了。这相当于是一个顾客对应的一个订单。

package SimpleFactoryPattern.PizzaStore.Order;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import SimpleFactoryPattern.PizzaStore.pizza.CheesePizza;
import SimpleFactoryPattern.PizzaStore.pizza.GreekPizza;
import SimpleFactoryPattern.PizzaStore.pizza.Pizza;

public class OrderPizza {
	
	public OrderPizza() {
		Pizza pizza = null;
		String orderType; //订购披萨类型
		do {
			//进入选择系统,匹配披萨种类
			orderType = getType();
			if(orderType.equals("greek")) {
				//创建不同的披萨对象
				pizza = new GreekPizza();
				pizza.setName("希腊披萨");
			}else if(orderType.equals("cheese")){
				pizza = new CheesePizza();
				pizza.setName("奶酪披萨");
			}else {
				break;
			}
			//输出披萨制作过程
			pizza.prepare();
			pizza.bake();
			pizza.cut();
			pizza.box();
		} while (true);
	}

	private String getType() {
		try {
			//顾客告诉前台,要什么口味的披萨,前台在系统中选择
			BufferedReader bfReader = new BufferedReader(new InputStreamReader(System.in));
			System.out.println("input pizza type:");
			String string;
			string = bfReader.readLine();
			return string;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return "";
		}
		
	}
}

客户端代码:

package SimpleFactoryPattern.PizzaStore.Order;

//相当于一个客户端,发出订购任务
public class PizzaStore {
	public static void main(String[] args) {
		new OrderPizza(); 
	}
}
/*
运行结果:
input pizza type:
greek
希腊披萨材料准备好了!
希腊披萨baking
希腊披萨cutting
希腊披萨boxing
input pizza type:
cheese
奶酪披萨材料准备好了!
奶酪披萨baking
奶酪披萨cutting
奶酪披萨boxing
input pizza type:
xxx

*/

由上述代码我们可以观察到:

  他违反了设计模式的ocp原则,即对扩展开放,对修改关闭。当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码。就上述代码而言:如果在其他地方也有创建Pizza对象的代码,我们便需要对这些地方都进行修改。直接new该对象会对该对象耦合严重,更换对象,所有new对象的地方都需要修改一遍,因此就违背了我们软件设计的开闭原则。

  再通俗易懂的说就是,上面的OrderPizza类就类似于,每个顾客点单后产生的一个订单,每一个订单中都需要去new对象,如果新增加了pizza种类,每一个订单中OrderPizza() 这个方法都需要进行修改,订单一多那简直是麻烦透顶了!根本就是给人找事儿!!!

那么如何改进这段代码呐?

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

  至此我们引入简单工厂,让工厂去给我们制作披萨,增加SimpleFactory类:

package SimpleFactoryPattern.PizzaStore.Order;
//简单工厂类

import SimpleFactoryPattern.PizzaStore.pizza.CheesePizza;
import SimpleFactoryPattern.PizzaStore.pizza.GreekPizza;
import SimpleFactoryPattern.PizzaStore.pizza.Pizza;

public class SimpleFactory {
	//根据orderType 返回对应的Pizza对象
	public Pizza creatPizza(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("奶酪披萨");
		}
		
		return pizza;	
	}
}

同时对OrderPizza进行修改:

package SimpleFactoryPattern.PizzaStore.Order;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import SimpleFactoryPattern.PizzaStore.pizza.Pizza;

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.creatPizza(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 bfReader = new BufferedReader(new InputStreamReader(System.in));
			System.out.println("input pizza type:");
			String string;
			string = bfReader.readLine();
			return string;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return "";
		}
		
	}
}

客户端代码改变:

package SimpleFactoryPattern.PizzaStore.Order;

//相当于一个客户端,发出订购任务
public class PizzaStore {
	public static void main(String[] args) {
		//使用简单工厂模式
        //将使用功能和创建产品分开执行
		new OrderPizza(new SimpleFactory());
		System.out.println("退出程序");
	}
}
/*
结果:
input pizza type:
greek
使用简单工厂模式
希腊披萨材料准备好了!
希腊披萨baking
希腊披萨cutting
希腊披萨boxing
input pizza type:
cheese
使用简单工厂模式
奶酪披萨材料准备好了!
奶酪披萨baking
奶酪披萨cutting
奶酪披萨boxing
input pizza type:
xx
使用简单工厂模式
 订购披萨失败 
退出程序

*/

  简单工厂模式的实现到此就结束了,但是简单工厂模式又被称为静态工厂方法。原因就是它把SimpleFactory类中的createPizza()方法变成了静态,同时代码进行了一些改动。

package SimpleFactoryPattern.PizzaStore.Order;
//简单工厂类

import SimpleFactoryPattern.PizzaStore.pizza.CheesePizza;
import SimpleFactoryPattern.PizzaStore.pizza.GreekPizza;
import SimpleFactoryPattern.PizzaStore.pizza.Pizza;

public class SimpleFactory {
	//根据orderType 返回对应的Pizza对象
	public Pizza creatPizza(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("奶酪披萨");
		}
		
		return pizza;	
	}
	
	public static Pizza creatPizza2(String orderType){
		
		Pizza pizza = null;
		
		System.out.println("使用简单工厂模式2");
		
		if(orderType.equals("greek")) {
			//创建不同的披萨对象
			pizza = new GreekPizza();
			pizza.setName("希腊披萨");
		}else if(orderType.equals("cheese")){
			pizza = new CheesePizza();
			pizza.setName("奶酪披萨");
		}
		
		return pizza;	
	}
}

OderPizza中方法的调用进行了改变:

package SimpleFactoryPattern.PizzaStore.Order;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import SimpleFactoryPattern.PizzaStore.pizza.Pizza;

public class OrderPizza2 {
	
		Pizza pizza = null;
		String orderType = "";
		
		public OrderPizza2() {
			do {
				orderType = getType();
				pizza = SimpleFactory.creatPizza2(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 bfReader = new BufferedReader(new InputStreamReader(System.in));
				System.out.println("input pizza type:");
				String string;
				string = bfReader.readLine();
				return string;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return "";
			}
			
		}
}

客户端:

package SimpleFactoryPattern.PizzaStore.Order;

//相当于一个客户端,发出订购任务
public class PizzaStore {
	public static void main(String[] args) {
		//使用简单工厂模式
		/*
		 * new OrderPizza(new SimpleFactory()); 
		 * System.out.println("退出程序");
		 */
		
		new OrderPizza2();
	}
}

3.4 模式分析

  在简单工厂模式中,新的产品加入系统时,产品角色无须修改就可接纳新的产品,但对于工厂角色来说,增加新产品要修改源程序;工厂角色必须知道每一种产品,如何创建产品,以及何时向客户端提供产品。所以,简单工厂模式对于产品角色开﹣闭原则是成立的,而对于工厂角色开﹣闭原则是不成立的,简单工厂角色只在有限的程度上支持开﹣闭原则。
   简单工厂模式的要点是当用户需要什么时,只需要传人一个正确的参数,就可以获取所需要的对象,而无须知道其创建细节。

3.4.1 简单工厂模式的优点

  1. 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;
  2. 简单工厂模式通过这法实现了对责任的分割,它提供了专门的工厂类用于创建对象。客户端无须知道所创建的具产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工一模式就可以减少用户的记忆量。新的产品加人系统时,产品角色无须修改就可被接纳。

3.4.2 简单工厂模式的缺点

  1. 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
  2. 简单工厂模式如果使用了静态工厂方法,就会造成工厂角色无法形成基于继承的等级结构。

3.4.3 模式应用环境

  1. 工厂类负责创建的对象比较少。由于创建的对象较少,不会造就工厂方法中的业务逻辑太过复杂。
  2. 客户端只知道传人工厂类的参数,对于如何创建对象不关。客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值