* 24种设计模式——工厂模式

本文详细介绍了工厂方法模式的概念、应用场景及其实现方式。通过女娲造人的例子,讲解了如何利用工厂方法模式来创建不同的人类对象,展示了该模式如何降低模块间的耦合并提高系统的扩展性。

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

核心:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

一、女娲造人的故事

1. 人类总称

public interface Human {
	public void getColor();
	public void talk();
}
2. 黑色人种

public class BlackHuman implements Human{
	public void getColor() {
		System.out.println("黑种人的皮肤是黑色的!");
	}
	public void talk() {
		System.out.println("黑人会说话,一般人听不懂!");
	}
}
3. 黄色人种

public class YellowHuman implements Human{
	public void getColor() {
		System.out.println("黄种人的皮肤是黄色的!");
	}
	public void talk() {
		System.out.println("黄程人说话,一般是双字节的!");
	}
}
4. 白色人种

public class WhiteHuman implements Human{
	public void getColor() {
		System.out.println("白色人种的皮肤是白色的!");
	}
	public void talk() {
		System.out.println("白色人会话说,一般是单字节的!");
	}
}
5. 抽象人类工厂类

public abstract class AbstractHumanFactory {
	public abstract <T extends Human> T createHuman(Class<T> c);
}
6.  人类创建工厂

public class HumanFactory extends AbstractHumanFactory{
	public <T extends Human> T createHuman(Class<T> c) {
//		return c.newInstance();
		Human human = null;
		try {
			human = (T)Class.forName(c.getName()).newInstance();
		} catch (Exception e) {
			System.out.println("人种生成错误");
		}
		return (T) human;
	}
}
7. 女娲类

public class NvWa {
	public static void main(String[] args) {
		AbstractHumanFactory YinYangLu = new HumanFactory();
		Human whiteHuman = YinYangLu.createHuman(WhiteHuman.class);
		whiteHuman.getColor();
		whiteHuman.talk();
		
		BlackHuman blackHuman = YinYangLu.createHuman(BlackHuman.class);
		blackHuman.getColor();
		blackHuman.talk();
		
		YellowHuman yellowHuman = YinYangLu.createHuman(YellowHuman.class);
		yellowHuman.getColor();
		yellowHuman.talk();
	}
}
二、工厂方法模式的定义

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

1. 抽象产品类

public abstract class Product {
	//产品类的公共方法
	public void method1() {
		//业务处理
	}
	//抽象方法
	public abstract void method2();
}
2. 具体产品类,可有多个,都继承于抽象产品类

public class ConcreteProduct1 extends Product{
	public void method2() {
		//业务处理
	}
}
public class ConcreteProduct2 extends Product{
	public void method2() {
		//业务处理
	}
}
3. 抽象工厂类,负责定义产品对象的产生

public abstract class Creator {
	//创建一个产品对象,其输入参数类型可以自行设置,通常为String、Enum、Class等,当然也可以为空
	public abstract <T extends Product> T createProduct(Class<T> c);
}
4. 具体工厂类
public class ConcreteCreator extends Creator{
	public <T extends Product> T createProduct(Class<T> c) {
		Product product = null;
		try {
			product = (Product) Class.forName(c.getName()).newInstance();
		} catch (Exception e) {
			//异常处理
		}
		return (T) product;
	}
}
5. 场景类

public class Client {
	public static void main(String[] args) {
		Creator creator = new ConcreteCreator();
		Product product = creator.createProduct(ConcreteProduct1.class);
		//业务处理
	}
}

三、工厂方法模式的优点

1. 一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或约束字符串)就可以了,不用知道创建对象的艰辛过程,降低模块间的耦合。

2. 扩展性好,要加一个棕色人种,只用增加一个BrownHuman类。

3. 屏蔽产品类,调用者只用关心产品的接口,只要接口不变,系统 中的上层模块就不要发生变化,因为产品类的实例化是由工厂类负责的,一个产品对象具体由哪个产品生成是由工厂类决定的。在开发中,如果使用JDBC连接数据库,数据库从MySQL切换到Oracle,需要改动的地方就是切换一下驱动名称(前提是SQL语句是标准语句),其他都不用改,这是工厂方法模式的一个直接案例。

4. 符合迪米特法则:高层模块只需要知道产品的抽象类,其他的实现类都不用关心,不需要的就不要去交流。

    符合依赖倒置原则:只依赖产品类的抽象;

    符合里氏替换原则:使用产品子类替换产品父类也可以。

四、工厂方法的使用场景

1. 工厂方法模式是new一个对象的替代品,所以在所有生成对象的地方都可以使用,但是需要慎重地考虑是否要增加一个工厂类进行管理,增加代码的复杂度。

2. 需要灵活的、可扩展的框架时,例如需要设计一个连接邮件服务器的框架,有三种网络协议可选择:POP3、IMAP、HTTP,我们就可以把这三种连接方法作为产品类,定义一个接口如IConnectMail,然后定义对邮件的操作方法,用不同的方法实现 三个具体的产品类(也就是连接方式)再定义一个工厂方法,按照不同的传入条件,选择不同的连接方式。

五、工厂方法模式的扩展

1. 缩小为简单工厂模式

在类图中去掉AbstractHumanFactory,同时把HumanFactory中的createHuman方法修改为static静态方法,简化了工厂类的创建过程。

而场景类中只用调用下列代码,就可产生一个实例类:

Human whiteHuman = HumanFactory.createHuman(WhiteHuman.class);

缺点:工厂类的扩展比较,不符合开闭原则。

2. 升级为多个工厂类

用于对多种产品(有各自特性或初始化方法)的情况下,可能不适合用同一个工厂,这时可用多个工厂,各工厂各自的产品。

每个产品都对应一个创建类,好处是创建类的职责清晰,结构简单,但给可扩展性和可维护性带来一定影响。比如,如果要扩展一个产品类,就需要建立一个相应的工厂类,这样就增加了扩展的难度。
在复杂的应用中一般采用多工厂方法,然后再增加一个协调类,避免调用者与各个子工厂交流,协调类的作用是封闭子工厂类,对高层模块提供统一的访问接口。

抽象工厂类:

public abstract class AbstractHumanFactory {
	public abstract Human createHuman();
}

黑种人工厂类:

public class BlackHumanFactory extends AbstractHumanFactory{
	public Human createHuman() {
		return new BlackHuman();
	}
}
白种人工厂类:

public class WhiteHumanFactory extends AbstractHumanFactory{
	public Human createHuman() {
		return new WhiteHuman();
	}
}
黄种人工厂类:

public class YellowHumanFactory extends AbstractHumanFactory{
	public Human createHuman() {
		return new YellowHuman();
	}
}
场景类:

public class NvWa {
	public static void main(String[] args) {
		Human whiteHuman = (new WhiteHumanFactory()).createHuman();
		whiteHuman.getColor();
		whiteHuman.talk();
		
		Human blackHuman = (new BlackHumanFactory()).createHuman();
		blackHuman.getColor();
		blackHuman.talk();
		
		Human yellowHuman = (new YellowHumanFactory()).createHuman();
		yellowHuman.getColor();
		yellowHuman.talk();
	}
}

3. 单例类

需要单例的类

public class Singleton {
	private Singleton(){
		
	}
	public void doSomething() {
		System.out.println("111");
	}
}
单例Factory方法

public class SingletonFactory {
	private static Singleton singleton;
	static{
		try {
			Class cl = Class.forName(Singleton.class.getName());
			Constructor constructor = cl.getDeclaredConstructor();
			constructor.setAccessible(true);
			singleton = (Singleton)constructor.newInstance();
		} catch (Exception e) {
			//异常处理
		}
	}
	public static Singleton getSingleton(){
		return singleton;
	}
}
4. 延迟初始化

一个对象初始化后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。

public class ProductFactory {
	private static final Map<String,Product> prMap = new HashMap<String,Product>();
	public static synchronized Product createProduct(String type) {
		Product product = null;
		if(prMap.containsKey(type)){
			return prMap.get(type);
		}else{
			if(type.equals("Product1")){
				product = new ConcreteProduct1();
			}else if(type.equals("Product2")){
				product = new ConcreteProduct2();
			}
			prMap.put(type, product);
		}
		return product;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值