项目代码地址
一、需求介绍
现公司数据库有一张表中的数据,需要通过外部接口将数据推送到别人的系统中。现有的问题是:
- 数据字段太多,而且双方系统实体字段不一致,每次都要通过get、set方法去对数据取值然后重新赋值。
- 如果后期需要添加数据或者减少数据,修改不方便。
二、设计模式选择
- 建造者模式(Builder):指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
- 适配器模式(Adapter):将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。我们这里选择对象
我们可以通过建造者模式去解决字段多且赋值困难问题,使用适配器模式去将我们系统的值转换为请求接口需要的值。
三、代码实现
1、准备实体类
- 本地需要被转换的对象LocalEmployee.java,即适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
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。
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 +
'}';
}
}
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 + '\'' +
'}';
}
}
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):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法。
package com.company.modeTest.builder;
/**
* 抽象建造者
* @param <O> 要构建的对象
*/
public interface BaseBuilder<O> {
O build();
}
- 对抽象建造者增强
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();
}
}
- 具体建造者
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;
}
}
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;
}
}
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)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
package com.company.modeTest.adapter;
/**
* 目标(Target)接口
* @param <F> 所要适配的数据源
* @param <T> 所要适配的对象,即需要的结果
*/
public interface Target<F,T> {
T adaptData(F fromData);
}
- 对把目标接口进行增强,暴露建造者,使用户可以自定义构建数据,无需了解底层代码
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)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。在这里,我们调用建造者,对接口必须的数据数据进行转换,并返回接口所需数据对象。
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、代码测试
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);
}
}
测试结果: