项目背景:
项目是为一家第三方物流公司做的仓储管理系统(WMS),由于国内电商的盛行,第三方物流仓储也迎来了大的发展,老旧系统在仓储利用率和操作效率上需要提高,且老旧系统在应对新业务方面处理能力不足.所以系统需要在这几个方面进行改进,本文只抽取对新业务处理的部分问题进行讨论设计模式的最佳实践;
问题描述:
电商第三方仓库,需要和大量的快递公司进行打交道,需要通过call接口的形式去不同的快递公司获取快递单号,又需要根据不同的快递公司进行打印相应的运单格式.且不确定哪些快递公司.比如A客户租赁的仓库只发顺丰的快递,B客户可以发中通申通的快递,由于仓库分布在全国各地,将来谈的不同客户可能要求各种稀奇古怪等不确定的快递公司;所以架构在处理此处业务的时候,必需保证足够的灵魂;
解决方案:
想法:
是否可以设计一个架构,可以使自由配置客户所对应的快递公司,如果有新的快递公司进来,可以在不入侵代码的情况获取新的快递公司单号,打印相应的快递单号;
实现: 需要的技术
抽象工厂模式+反射
抽象工厂:
定义:提供一个接口,可以创建一系列相互依赖的对象,而无需指定他们的具体类;
结构:
抽象工厂的代码实现(不方便放项目代码,这里我们拿最简单保存用户信息到不同的数据库举例)
// IUser 接口
public interface IUser {
public void insert(User user);
public IUser getUser(int uid);
}
// IUser 接口实现 (mysql,oracle 同理)
public class MysqlUser implements IUser{
public void insert(User user) {
System.out.println("add user to mysql");
}
public IUser getUser(int uid) {
System.out.println("get user from mysql");
return null;
}
}
// IFactory 接口
public interface IFactory {
public IUser createUser();
}
// IFactory 接口的 mysql 实现
public class MysqlFactory implements IFactory{
public IUser createUser() {
return new MysqlUser();
}
}
// 客户端代码调用
public class Client {
public static void main(String[] args){
User user=new User();
//如果 换成其他数据,只需要更换 MysqlFactory 即可
// 在WMS项目中,工厂实现的时候可以调用不同快递公司的实现
IFactory factory=new MysqlFactory();
IUser userOperation=factory.createUser();
userOperation.getUser(1);
userOperation.insert(user);
}
}
此时我们虽然实现了抽象工厂,仅仅通过改一行代码或者添加不同的判断,就可以实现快递公司的选择;但是此时依然存在一个问题,开发阶段我实现了3家快递公司的工厂实现.项目上线后,如果再有2家快递公司的业务需要添加,怎么办呢.修改代码,重新开发两个快递公司的实现.打包发布?理论上也可以,但这样做对于一个有Android扫描枪,将来还有C/S端的程序,升级起来是非常困难的,所以一个让用户无感升级的设计是非常重要的,同时也可以大大减轻维护人员的工作量.此时我们就引入了反射机制;
反射
定义:反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为程序语言的反射机制
逻辑实现:
- 首先我们将各个工厂的实现封装成不同的DLL(或jar包)
- 其次我们将不同快递公司需要调用哪个工厂实现的对应关系写入到数据或者xml配置
- 扫描枪或者PC选择不同快递公司时,通过配置和反射去加载不同的工程实现
- 如果首次加载找不到对应关系的DLL(或jar包),则去服务器自动下载
代码实现:
Assembly assembly = Assembly.LoadFile("程序集路径,不能是相对路径"); // 加载程序集(EXE 或 DLL)
dynamic obj = assembly.CreateInstance("类的完全限定名(即包括命名空间)"); // 创建类的实例
IFactory factory=obj;