`

系统融合 -- 适配器模式

阅读更多

什么是系统融合

 

何谓系统融合,简单的说就是把两个或者多个系统融合为一个系统。在一个公司中,为了降低维护成本,会遇到将两个或者多个业务类似的系统融合成一个系统的场景。有人会问为什么同一个公司会有多个类似的系统,最常见的就是A电商公司收购了B电商公司,为了降低维护成本就需要对两套系统进行融合。当然还有一些原因是公司内耗,这里不一一列举。

 

两个系统融合,最大的困难就是接口不统一。比如同样是商品接口,AB两个公司的接口名可能不同,商品类的定义也不同。这时为了让外部系统调用这两个接口无感知,就需要一个统一的接口,这就产生了适配器模式。

 

适配器模式

 

在解决系统融合之前,先来看看“适配器模式”。生活中经常会遇到适配器,比如:把电器的两项插头转换为三项插头;笔记本电脑的电流适配器,把220伏转换为12伏;自来水管分流口等等。他们都有一个共同的特征,在原本不匹配的两个接口之间建立起桥梁,把二者链接起来。换成程序员的语言即为:将一个类的接口,转换成客户期望的另一个接口,适配器让原本接口不兼容的类连接起来。适配器模式类图:



 

 

类图很简单,大致分为四类角色:

1、客户端Client,该客户端只接受Target类型的接口。

2、抽象接口Target(抽象类也可以),定义了公共的方法。

3 适配器Adapter,实现了Target接口,并拥有一个真实的Adaptee类型的成员变量adaptee。在其request方法中会调用adapteerealRequest方法。

4、被适配角色AdapteerealRequest方法包含真实的业务逻辑实现。

 

使用适配器模式进行系统融合

 

上面类图中只画出了一个Adapter适配器,在“系统融合”的场景中会为同一个接口创建多个Adapter适配器(这里是两个),分别对应多个类似业务。这里以AB两个电商系统融合为例,两套系统有数十个接口我们需要在AB两个系统之上新建一个“适配器”系统。为了顺应现在的前中台系统建设潮流,设计架构上对前中台进行区分,整体架构调整如下:




AB两个系统没有融合前,他们都各自对应自己的前台系统,架构说明如下:

1AB两个公司合并前,都有各自对应的前台系统和中台系统。如图中绿色箭头所示。

2、现在AB两个公司合并,为了降低维护成本,以及增加用户体验,只维护一个前台系统。为了在系统融合期间,外部用户可以正常访问AB前台系统,这里增加一个新前台系统

3、同时为了兼容老数据,AB两个系统保持原样不变,新增一个适配器系统,对AB两个系统中的公共业务接口进行适配。接口调用流程,如上图中红色箭头所示,统一后的“前台系统”首先调用“适配器系统”,根据参数适配到AB系统中。

4AB两套系统在融合前 虽然业务类似,但也就自己的个性化业务,统一后的“前台系统”直接调用AB系统原接口即可。如上图中的紫色箭头所示。

5、当“新前台系统”开发完成并上线后,即可关闭两个老的前台系统。只维护一套新前台系统即可

 

通过上述系统架构,即可快速完成新系统的融合,又不影响老系统的访问,为了防止老客户对新系统的不适应,还可以让三个前台系统并行运行一段时间。是不是有种“酷毙了”的赶脚。

 

这个强大的系统架构设计的核心就是设计新的适配器系统,这个系统里设计有多个数据接口(AB系统公共的接口),每个接口都是采用适配器模式AB两个系统的接口进行封装,让新的前台系统以为是一个接口。

下面就以商品接口为例,对适配器模式进行讲解。

 

适配器示例--融合“商品接口”

 

根据上述新系统架构,主要分为4个系统:“A系统“B系统、新适配器系统、新前台系统。作为示例不会把4个系统都搬出来,这里使用一个java application程序进行模拟,如下:

 



 

 

其中两个老系统的商品类ProductAProductB业务很类似:

public class ProductA {
    private Integer a_id;//A系统 商品id
    private String a_name;//A系统 商品名称
private String a_category;//A系统 商品分类
 
//省略其他setter、getter方法
}
 
public class ProductB {
    private Integer b_id;//B系统 商品id
    private String b_name;//B系统 商品名称
    private String b_category;//B系统 商品分类
private Integer venderId;//商家Id
 
//省略其他setter、getter方法
}

可以看到其中三个字段是相同业务类型,ProductB中多一个成员变量venderId(商家Id)。现在要在新适配器系统中,定义新商品类Product,需要包含两个系统中所有业务,定义如下:

public class Product {
    private Integer id;//新商品id
    private String name;//新商品名称
    private String category;//新商品分类
private Integer venderId;//商家Id
 
//省略其他setter getter方法
}

新商品对象定义完毕,现在进行接口适配,这里以A系统商品接口为例(B系统类似):

被适配角色ProdcutManagerA(接口)、ProdcutManagerAImpl(实现类):

public interface ProdcutManagerA {
    ProductA getById(Integer id);
}
 
public class ProdcutManagerAImpl implements ProdcutManagerA{
    public ProductA getById(Integer id){
        ProductA productA = new ProductA();
        productA.setA_id(1000);
        productA.setA_name("A系统彩电");
        productA.setA_category("A系统_家电类");
 
        return productA;
    }
}
 

 

新接口:新接口返回类型是新商品类Product

/**
 * 新商品管理接口类
 * Created by gantianxing on 2017/11/4.
 */
public interface ProdcutAdapter {
    //新商品接口
    Product getById(Integer id);
}
 

 

A系统适配器 需要实现新接口:

/**
 * A系统商品接口 适配器
 * Created by gantianxing on 2017/11/4.
 */
public class ProdcutAdapterAImpl implements ProdcutAdapter {
 
    private ProdcutManagerA prodcutManagerA;
 
    public ProdcutAdapterAImpl(ProdcutManagerA prodcutManagerA){
        this.prodcutManagerA = prodcutManagerA;
    }
 
    public Product getById(Integer id) {
        ProductA productA = prodcutManagerA.getById(id);
        if(productA != null){
            Product product = new Product();
            product.setId(productA.getA_id());
            product.setName(productA.getA_name());
            product.setCategory(productA.getA_category());
            return product;
        }
        return null;
    }
}

 

可以看到ProdcutAdapterAImpl适配器,把“A系统商品接口 转换为新前台系统适配的接口。这里只展示类A系统适配器创建过程,B系统适配器ProdcutAdapterBImpl创建过程类似,不再累述。

 

下面是见证奇迹的时候,新前台系统模拟类Client:可以不依赖AB系统的情况下,采用统一的接口调用老AB系统的商品接口:

 

/**
 * 客户端,模拟前台系统
 * Created by gantianxing on 2017/11/4.
 */
public class Client {
 
    public static void main(String[] args) {
        //新建 两个适配器对象,在真实系统中 通过使用rpc框架 客户端只会直接依赖ProdcutAdapter接口
        ProdcutAdapter prodcutAdapterAImpl = new ProdcutAdapterAImpl(new ProdcutManagerAImpl());
        ProdcutAdapter prodcutAdapterBImpl = new ProdcutAdapterBImpl(new ProdcutManagerBImpl());
 
        Product p1 = prodcutAdapterAImpl.getById(1000);//获取A系统商品 1000
        Product p2 = prodcutAdapterBImpl.getById(1001);//获取B系统商品 1001
 
        System.out.println(p1.toString());
        System.out.println(p2.toString());
    }
}

 

 

在本实例中,也许已经注意到Client中依赖了新老系统中的具体的实现类:ProdcutAdapterAImplProdcutManagerAImplProdcutAdapterBImplProdcutManagerBImpl

 

结合RPC框架进行解耦

 

但在真实的系统中通过引入RPC框架和Spring IOC注入,新前台系统只会依赖一个适配器接口类:ProdcutAdapter;同时新建的“适配器系统”只依赖老AB系统的接口类:ProdcutManagerAProdcutManagerB。如下图所示:

 




可以看到新前台系统、以及新增的适配器系统只依赖接口,不依赖具体的实现,与AB系统做到完全解耦。

 

也许你已注意到 上图有点类似适配器模式的类图,其实这个适配器系统 就是利用适配器模式为基础 封装出的一个新系统而已(把模式放大化使用)。

 

 

该模式的要点,就是转换接口以适配客户端业务需求。 关于适配器模式就总结到这里。

 

出处:

http://moon-walker.iteye.com/blog/2398721

  • 大小: 12.5 KB
  • 大小: 34.2 KB
  • 大小: 17.1 KB
  • 大小: 28.5 KB
0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics