设计模式的使用——建造者模式+适配器模式

项目代码地址

一、需求介绍

现公司数据库有一张表中的数据,需要通过外部接口将数据推送到别人的系统中。现有的问题是:

  • 数据字段太多,而且双方系统实体字段不一致,每次都要通过get、set方法去对数据取值然后重新赋值。
  • 如果后期需要添加数据或者减少数据,修改不方便。

二、设计模式选择

  • 建造者模式(Builder):指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
  • 适配器模式(Adapter) :将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。我们这里选择对象
      我们可以通过建造者模式去解决字段多且赋值困难问题,使用适配器模式去将我们系统的值转换为请求接口需要的值。

三、代码实现

1、准备实体类

  • 本地需要被转换的对象LocalEmployee.java,即适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
java 复制代码
package com.company.modeTest.dto;

public class LocalEmployee {

    private Integer id = 1;
    private String name = "我类个乖乖";
    private Integer age = 18;
    private Integer sex = 1;
    private String address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age='" + age + '\'' +
                ", sex=" + sex +
                ", address=" + address +
                '}';
    }
}
  • 远程接口需要的对象:RemoteEmployee.java、RemotePosition.java、RemoteRole.java
java 复制代码
package com.company.modeTest.dto;

import java.util.List;

public class RemoteEmployee {

    private Integer remoteId;
    private String remoteName;
    private Integer remoteAge;
    private Integer remoteSex;
    private String remoteAddress;
    private List<RemoteRole> roles;
    private RemotePosition position;

    public List<RemoteRole> getRoles() {
        return roles;
    }

    public void setRoles(List<RemoteRole> roles) {
        this.roles = roles;
    }

    public RemotePosition getPosition() {
        return position;
    }

    public void setPosition(RemotePosition position) {
        this.position = position;
    }

    public Integer getRemoteId() {
        return remoteId;
    }

    public void setRemoteId(Integer remoteId) {
        this.remoteId = remoteId;
    }

    public String getRemoteName() {
        return remoteName;
    }

    public void setRemoteName(String remoteName) {
        this.remoteName = remoteName;
    }

    public Integer getRemoteAge() {
        return remoteAge;
    }

    public void setRemoteAge(Integer remoteAge) {
        this.remoteAge = remoteAge;
    }

    public Integer getRemoteSex() {
        return remoteSex;
    }

    public void setRemoteSex(Integer remoteSex) {
        this.remoteSex = remoteSex;
    }

    public String getRemoteAddress() {
        return remoteAddress;
    }

    public void setRemoteAddress(String remoteAddress) {
        this.remoteAddress = remoteAddress;
    }

    @Override
    public String toString() {
        return "RemoteEmployee{" +
                "remoteId=" + remoteId +
                ", remoteName='" + remoteName + '\'' +
                ", remoteAge='" + remoteAge + '\'' +
                ", remoteSex=" + remoteSex +
                ", remoteAddress='" + remoteAddress + '\'' +
                ", roles=" + roles +
                ", position=" + position +
                '}';
    }
}
java 复制代码
package com.company.modeTest.dto;

public class RemotePosition {
    private Integer positionId;
    private String positionName;

    public Integer getPositionId() {
        return positionId;
    }

    public void setPositionId(Integer positionId) {
        this.positionId = positionId;
    }

    public String getPositionName() {
        return positionName;
    }

    public void setPositionName(String positionName) {
        this.positionName = positionName;
    }

    @Override
    public String toString() {
        return "RemotePosition{" +
                "positionId=" + positionId +
                ", positionName='" + positionName + '\'' +
                '}';
    }
}
java 复制代码
package com.company.modeTest.dto;

public class RemoteRole {
    private Integer roleId;
    private String roleName;

    public Integer getRoleId() {
        return roleId;
    }

    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    @Override
    public String toString() {
        return "RemoteRole{" +
                "roleId=" + roleId +
                ", roleName='" + roleName + '\'' +
                '}';
    }
}

2、编写建造者模式代码

  • 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法。
java 复制代码
package com.company.modeTest.builder;

/**
 * 抽象建造者
 * @param <O> 要构建的对象
 */
public interface BaseBuilder<O> {
    O build();
}
  • 对抽象建造者增强
java 复制代码
package com.company.modeTest.builder;

/**
 * 对抽象建造者进行功能增强,使其支持..and()...的链式编码风格
 * @param <O> 要构建的对象
 * @param <B> 被构建对象的具体建造者
 */
public abstract class AbstractParamBuilderAdapter<O,B extends BaseBuilder<O>> {

    private B builder;

    void setBuilder(B builder) {
        this.builder = builder;
    }

    protected final B getBuilder() {
        return builder;
    }

    public B and() {
        return getBuilder();
    }
}
  • 具体建造者
java 复制代码
package com.company.modeTest.builder;

import com.company.modeTest.dto.RemoteEmployee;
import com.company.modeTest.dto.RemotePosition;

public class PositionBuilder extends AbstractParamBuilderAdapter<RemoteEmployee,EmployeeBuilder> implements BaseBuilder<RemotePosition>{
    private final RemotePosition remotePosition = new RemotePosition();

    public PositionBuilder positionId(Integer positionId){
        remotePosition.setPositionId(positionId);
        return this;
    }

    public PositionBuilder positionName(String positionName){
        remotePosition.setPositionName(positionName);
        return this;
    }
    @Override
    public RemotePosition build() {
        return remotePosition;
    }
}
java 复制代码
package com.company.modeTest.builder;

import com.company.modeTest.dto.RemoteEmployee;
import com.company.modeTest.dto.RemoteRole;

public class RoleBuilder extends AbstractParamBuilderAdapter<RemoteEmployee,EmployeeBuilder> implements BaseBuilder<RemoteRole>{
    private final RemoteRole remoteRole = new RemoteRole();

    public RoleBuilder roleId(Integer roleId){
        remoteRole.setRoleId(roleId);
        return this;
    }

    public RoleBuilder roleName(String roleName){
        remoteRole.setRoleName(roleName);
        return this;
    }
    @Override
    public RemoteRole build() {
        return remoteRole;
    }
}
java 复制代码
package com.company.modeTest.builder;

import com.company.modeTest.dto.RemoteEmployee;
import com.company.modeTest.dto.RemoteRole;
import java.util.ArrayList;
import java.util.List;

public class EmployeeBuilder implements BaseBuilder<RemoteEmployee>{
    private final RemoteEmployee remoteEmployee = new RemoteEmployee();
    private final List<RoleBuilder> roleBuilders = new ArrayList<>();
    private final List<RemoteRole> roles = new ArrayList<>();
    private PositionBuilder positionBuilder;

    public EmployeeBuilder remoteId(Integer remoteId){
        remoteEmployee.setRemoteId(remoteId);
        return this;
    }

    public EmployeeBuilder remoteName(String remoteName){
        remoteEmployee.setRemoteName(remoteName);
        return this;
    }

    public EmployeeBuilder remoteAge(Integer remoteAge){
        remoteEmployee.setRemoteAge(remoteAge);
        return this;
    }
    public EmployeeBuilder remoteSex(Integer remoteSex){
        remoteEmployee.setRemoteSex(remoteSex);
        return this;
    }
    public EmployeeBuilder remoteAddress(String remoteAddress){
        remoteEmployee.setRemoteAddress(remoteAddress);
        return this;
    }
    public RoleBuilder roles(){
        RoleBuilder roleBuilder = new RoleBuilder();
        roleBuilder.setBuilder(this);
        roleBuilders.add(roleBuilder);
        return roleBuilder;
    }
    public PositionBuilder position(){
        if (positionBuilder==null){
            positionBuilder = new PositionBuilder();
        }
        positionBuilder.setBuilder(this);
        return positionBuilder;
    }
    @Override
    public RemoteEmployee build() {
        if (positionBuilder!=null){
            remoteEmployee.setPosition(positionBuilder.build());
        }
        if (roleBuilders.size()>0){
            for (RoleBuilder roleBuilder : roleBuilders) {
                roles.add(roleBuilder.build());
            }
            remoteEmployee.setRoles(roles);
        }
        return remoteEmployee;
    }


}

3、编写适配器模式代码

  • 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
java 复制代码
package com.company.modeTest.adapter;

/**
 * 目标(Target)接口
 * @param <F> 所要适配的数据源
 * @param <T> 所要适配的对象,即需要的结果
 */
public interface Target<F,T> {

    T adaptData(F fromData);

}
  • 对把目标接口进行增强,暴露建造者,使用户可以自定义构建数据,无需了解底层代码
java 复制代码
package com.company.modeTest.adapter;


import com.company.modeTest.builder.BaseBuilder;

/**
 * @param <D> 被构架你对象的建造者
 * @param <O> 被构建的对象
 * @param <F> 所要适配的数据源
 */
public abstract  class AbstractDataTarget<D extends BaseBuilder<O>,O,F> implements Target<F,O> ,BaseBuilder<O>{
    public D dataBuilder;

    public D addInfo(){
        return dataBuilder;
    }

    @Override
    public O build() {
        return dataBuilder.build();
    }
}
  • 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。在这里,我们调用建造者,对接口必须的数据数据进行转换,并返回接口所需数据对象。
java 复制代码
package com.company.modeTest.adapter;

import com.company.modeTest.builder.EmployeeBuilder;
import com.company.modeTest.dto.LocalEmployee;
import com.company.modeTest.dto.RemoteEmployee;

public class EmployeeAdapter extends AbstractDataTarget<EmployeeBuilder, RemoteEmployee, LocalEmployee>{

    public EmployeeAdapter() {
        dataBuilder = new EmployeeBuilder();
    }

    @Override
    public RemoteEmployee adaptData(LocalEmployee fromData) {
        return dataBuilder
                .remoteId(fromData.getId())
                .remoteName(fromData.getName())
                .remoteAge(fromData.getAge())
                .remoteSex(fromData.getSex())
                .build();
    }
}

4、代码测试

java 复制代码
package com.company.modeTest;

import com.company.modeTest.adapter.EmployeeAdapter;
import com.company.modeTest.dto.LocalEmployee;
import com.company.modeTest.dto.RemoteEmployee;
import org.junit.Test;

public class MainTest {

    @Test
    public void test(){
        LocalEmployee localEmployee = new LocalEmployee();
        System.out.println("本地原始数据localEmployee---->"+localEmployee);
        EmployeeAdapter employeeAdapter = new EmployeeAdapter();
        RemoteEmployee remoteEmployee  = employeeAdapter.adaptData(localEmployee);
        System.out.println("适配获取的远程接口需要的数据remoteEmployee---->"+remoteEmployee);
        System.out.println("=====================用户开始自定义添加额外信息========");
        employeeAdapter.addInfo()
                .remoteAddress("中国加拿大省美市英县日本村")
                .position()
                    .positionId(2)
                    .positionName("技师")
                .and()
                .roles()
                    .roleId(3)
                    .roleName("太太")
                .and()
                .build();
        System.out.println("用户添加额外信息后remoteEmployee--->"+remoteEmployee);
    }

}

测试结果:

相关推荐
晨米酱3 小时前
JavaScript 中"对象即函数"设计模式
前端·设计模式
数据智能老司机8 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机9 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机9 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机9 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
使一颗心免于哀伤9 小时前
《设计模式之禅》笔记摘录 - 21.状态模式
笔记·设计模式
数据智能老司机1 天前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
烛阴1 天前
【TS 设计模式完全指南】懒加载、缓存与权限控制:代理模式在 TypeScript 中的三大妙用
javascript·设计模式·typescript
李广坤1 天前
工厂模式
设计模式