Java设计模式之抽象工厂模式的改进

文章探讨了如何改进抽象工厂模式,以减少产品类扩展时的改动。通过结合简单工厂和抽象工厂,利用反射技术,实现了更灵活的类实例化,降低了代码耦合,遵循了开放-封闭原则。文中通过生产文具的例子,阐述了改进过程,并指出了不同实现方式的优缺点。

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

抽象工厂模式在我的上一篇博文里已经详细介绍过,地址:https://blog.youkuaiyun.com/zaoan_2010/article/details/81987011

它的缺点主要体现在,需要新增产品时,做的改动比较多。针对这个缺点对抽象工厂模式做了一个改进。

1. 简单工厂+抽象工厂

举例说明:工厂需要生产中性笔和铅笔,中性笔有晨光牌和得力牌的。现如果需要增加油笔的生产,则需要增加油笔的抽象产品类及两个具体产品类(OilPike(油笔)、ChenGuangOilPike、DeLiOilPike),需要修改抽象工厂类及两个具体工厂类(StationaryFactory、ChenGuangFactory、DeLiFactory),改动比较多。

现通过简单工厂进行改进抽象工厂模式,去除StationaryFactory、ChenGuangFactory、DeLiFactory三个工厂类,用Stationary类替代,采用switch方法判断并实例化。

老样子,先上类图

从类图中就可以看出比抽象工厂简化了好多,下面上代码

抽象产品类

package main.mode.cxgcms2;

public abstract class GelPen {

	public abstract void product();
}

抽象产品类对应的具体产品类

package main.mode.cxgcms2;

public class ChenGuangGelPen extends GelPen{

	@Override
	public void product() {
		System.out.println("生产晨光牌中性笔");		
	}

}
package main.mode.cxgcms2;

public class DeLiGelPen extends GelPen{

	@Override
	public void product() {
		System.out.println("生产得力牌中性笔");
	}

}

抽象产品类2

package main.mode.cxgcms2;

public abstract class Pencil {

	public abstract void product();
}

抽象产品类2对应的具体产品类

package main.mode.cxgcms2;

public class ChenGuangPencil extends Pencil{

	@Override
	public void product() {
		System.out.println("生产晨光牌铅笔");
	}

}
package main.mode.cxgcms2;

public class DeLiPencil extends Pencil{

	@Override
	public void product() {
		System.out.println("生产得力牌铅笔");
	}

}

工厂类

package main.mode.cxgcms2;

public class Stationary {

	private static String type = "chenguang";//也可改为deli
	
	public static GelPen productGelPen() {
		GelPen gelPen = null;
		switch(type){
		case("chenguang"): 
			gelPen = new ChenGuangGelPen();
			break;
		case("deli"):
			gelPen = new DeLiGelPen();
			break;
		default:
			System.out.println("没有获取到正确类型");
			break;
		}
		return gelPen;
	}
	
	public static Pencil productPencil() {
		Pencil pencil = null;
		switch(type){
		case("chenguang"): 
			pencil = new ChenGuangPencil();
			break;
		case("deli"):
			pencil = new DeLiPencil();
			break;
		default:
			System.out.println("没有获取到正确类型");
			break;
		}
		return pencil;
	}
	
}

测试类

package main.mode.cxgcms2;

public class FactoryTest {

	public static void main(String[] args) {
		//需要生产晨光牌的中性笔和铅笔
		GelPen gelPen = Stationary.productGelPen();
		gelPen.product();
		
		Pencil pencil = Stationary.productPencil();
		pencil.product();
	}

}

测试结果:

可以看出,测试类中没有出现任何晨光或得力的字眼,达到了解耦的目的。

当然,也可以把工厂类中自定义的字段type提出来作为参数在调用时传入,不过这样就增加了调用方法(测试类)和工厂类的耦合性,不太好。

但简单工厂改进的抽象工厂模式仍然有其弊端。
如果现在增加一个生产商真彩,则需要改动类Stationary,增加switch分支,违背了封闭-开放原则。

可以换一个更好的方式去进行类的实例化--反射。

这样更灵活一些。

2. 反射+抽象工厂

这里只是更改了实例化的方式,只需要改动Stationary类即可,其他类的代码同上。

直接上代码

package main.mode.cxgcms3;

public class Stationary {
	
	private static String url = "main.mode.cxgcms3";
	private static String type = "ChenGuang";//也可改为DeLi
	
	public static GelPen productGelPen() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		String fullName = url + "." + type + "GelPen";
		Class<?> clazz =  Class.forName(fullName);
		GelPen gelPen = (GelPen) clazz.newInstance();
		return gelPen;
	}
	
	public static Pencil productPencil() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		String fullName = url + "." + type + "Pencil";
		Class<?> clazz =  Class.forName(fullName);
		Pencil pencil = (Pencil) clazz.newInstance();
		return pencil;
	}
	
}

可以看出,这样就比上面switch方式灵活了一下,如果增加生产商真彩,只需要改动type值即可,下面的方法不需要做改动。

当然了,这种在类中取String值的方式也不够灵活,也可以做进一步的更改,比如把这个值写在配置文件中,然后去配置文件取值,这样就更加灵活了。

此处不再赘述在配置文件取值的代码了。

 

说在后面:

本文主要是小猫看《大话设计模式》的笔记式的记录,方便以后查阅。

文中的例子是小猫自己想的,仅供参考,代码也有不够详尽的地方,主要是为了说明设计模式的思想。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值