设计模式-抽象工厂模式

抽象工厂模式是对工厂模式的一种改进。它提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

如何去理解这句话呢?

假设我们需要编写一个数据库访问程序,数据库会有很多表,那么对于每一张表的访问,我们可以理解为一种具体的对象。我们的数据库肯定不止一种,那么对于每一种数据库,我们都应该有相应的操作程序。这就是具体的需求了。

那么抽象工厂会如何去处理呢?首先,我们需要有针对于每张表的接口,接口抽象出了对表数据进行的具体操作。

public interface IUser {
	void insertUser();
	void selectUser();
}

public interface IDepartment {
	void insertDepartment();
	void selectDepartment();
}

然后,对于每个接口,分别会有对应的数据库访问类去实现这个接口

public class SqlServerUser implements IUser {
	@Override
	void insertUser(){
		sout("sqlserver插入用户");
	}
	
	@Override
	void selectUser() {
		sout("sqlserver查询用户");
	}
}

public class MysqlUser implements IUser{
	@Override
	void insertUser(){
		sout("mysql插入用户");
	}
	
	@Override
	void selectUser(){
		sout("mysql查询用户");
	}
}

…部门操作省略

有了上述的类,我们就可以开始编写工厂了。
首先需要一个抽象工厂,这个工厂拥有生产所有产品的能力

public abstract class AbstractSqlFactory {
	public abstract IUser createUser();
	public abstract IDepartment createDepartment();
}

可以看到,这里有两个方法,分别用来生产用户表操作类和组织表操作类。

具体的工厂如下

public class SqlServerFactory extends AbstractSqlFactory {
	@Override
	public IUser createUser() {
		return new SqlServerUser();
	}
	
	@Override
	public IDepartment createDepartment() {
		return new SqlServerDepartment();
	}
}

…mysql工厂省略

客户端调用如下

IFactory factory = new SqlServerFactory();
IUser user = factory.createUser();
user.insertUser();
user.selectUser();

利用抽象工厂,我们可以得到的好处是,易于交换产品系列。具体的工厂类在一个应用中只需要在初始化的时候出现一次,这样使得改变一个工厂变的非常容易。第二个好处是,它让创建具体的实例与客户端分离,客户端通过抽象接口操控实例。比如刚才的例子,客户端实际上只认识IUser和IDepartment,不会认识具体的类。

但抽象工厂也有不好的地方,虽然它在切换产品的时候很好用,但是如果我们想要增加一个表的操作,比如Project表,那么我们需要增加IProject、SqlServerProject、MysqlProject这三个类,还需要修改AbstractSqlFactory、SqlServerFactory、MysqlFactory这三个类,这是很糟糕的。增加一个操作,需要做这么大的改动。所以我们要对最基本的抽象工厂模式进行优化。

首先我们很容易想到的是,利用简单工厂模式来进行优化。取消工厂的抽象,换用一个通用的DataAccess类来进行处理

public class DataAccess {
	
	private static final String db = "SqlServer";
	
	public static IUser createUser() {
		switch(db) {
			case "SqlServer":
				return new SqlServerUser();
			case "Mysql":
				return new MysqlUser();
			default:
				return null;
		}
	}
	
	public static IDepartment createDepartment() {
		……
	}
}

这样客户端在调用的时候,只需要调用createUser或者createDepartment方法即可,解除了和具体工厂的耦合。要修改数据库实现的时候,也只需要修改db的值即可。但如果我们现在要增加一个对Oracle数据库的访问,事情就会变的麻烦起来。我们还需要修改每个方法中的switch语句,加入对Oracle数据库的判断。

那么有没有什么方法可以改进这种switch选择呢?其实我们可以利用反射来动态加载具体的类。这样这个类的路径可以写在一个变量中,或者干脆放在配置文件中,这样就解决了switch的问题。

相关demo可以参考我的gitee仓库
https://gitee.com/akitsuki-kouzou/DesignPatternDemo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值