组合模式与适配器模式结合使用

模板模式与适配器模式组合使用之合并站点数据



考虑一下这样的一个场景,网站模板应用到网站时需要合并站点数据。

站点数据(SiteData)是由页面(SitePageData)组成的,页面是由页面片段(SiteSegmentData)组成的,页面片段是由区域(SiteRegionData)组成的,区域是由版块(SiteAppData)组成的。

class SiteData{
List<SitePageData> pages;
}
class SitePageData{
List<SiteSegmentData> segments;
}
class SiteSegmentData{
List<SiteRegionData> regions;
}
class SiteRegionData{
List<SiteAppData> apps;
}


第一方案

public class SiteDataUtil {
public static void merge(SiteData from, SiteData to) {
// 判断是否需要合并
if (from != null && from.getPages() != null && !from.getPages().isEmpty()) {
// 如果要被合并的数据列表为空 , 则替换要合并过来的数据列表
if (to.getPages() == null) {
to.setPages(from.getPages());
return;
}
// 要被合并的数据列表
List<SitePageData> mergeToDatas = to.getPages();
// 要合并过来的数据列表
List<SitePageData> mergeFromDatas = from.getPages();

// 构造一个map进行一一对应合并
Map<String, SitePageData> map = new HashMap<String, SitePageData>();
// 循环当前每个数据到map中
for (SitePageData dataTo : mergeToDatas) {
String key = dataTo.getName();
map.put(key, dataTo);
}

// 循环每个要合并过来的每个数据, 一一对应地合并
for (SitePageData dataFrom : mergeFromDatas) {
String key = dataFrom.getName();
SitePageData dataTo = map.get(key);
// 如果map中存在相同key的数据,则进行合并
if (dataTo != null) {
merge(dataFrom, dataTo);
// 如果map中不存在则直接添加来源的data
} else {
to.getPages().add(dataFrom);
}
}
}
}

public static void merge(SitePageData from, SitePageData to) {
// 判断是否需要合并
if (from != null && from.getSegments() != null && !from.getSegments().isEmpty()) {
// 如果要被合并的数据列表为空 , 则替换要合并过来的数据列表
if (to.getSegments() == null) {
to.setSegments(from.getSegments());
return;
}
// 要被合并的数据列表
List<SiteSegmentData> mergeToDatas = to.getSegments();
// 要合并过来的数据列表
List<SiteSegmentData> mergeFromDatas = from.getSegments();

// 构造一个map进行一一对应合并
Map<String, SiteSegmentData> map = new HashMap<String, SiteSegmentData>();
// 循环当前每个数据到map中
for (SiteSegmentData dataTo : mergeToDatas) {
String key = dataTo.getLayoutId();
map.put(key, dataTo);
}

// 循环每个要合并过来的每个数据, 一一对应地合并
for (SiteSegmentData dataFrom : mergeFromDatas) {
String key = dataFrom.getLayoutId();
SiteSegmentData dataTo = map.get(key);
// 如果map中存在相同key的数据,则进行合并
if (dataTo != null) {
merge(dataFrom, dataTo);
// 如果map中不存在则直接添加来源的data
} else {
to.getSegments().add(dataFrom);
}
}
}
}
public static void merge(SiteSegmentData from, SiteSegmentData to) {
//合并segment
}
public static void merge(SiteRegionData from, SiteRegionData to) {
//合并region
}
}


优点

思路清晰,

缺点

面向过程,合并过程逻辑十分相似,可以认为是重复代码。



第二方案

从上面方案中总结出来,需要面向对象,于是我认为数据具备合并功能,在SiteData、SitePageData、SiteSegmentData、SiteRegionData、SiteAppData类去实现合并接口DataMergeable。

public interface DataMergable {

/**
* 合并数据
* @param from 执行数据合并的来源
*/
void mergeFrom(DataMergable from);

/**
* 获取数据源的子集
* @return
*/
List<DataMergable> getChildren();

/**
* 替换数据源的子集
* @param list
*/
void setChildren(List<DataMergable> children);

/**
* 添加数据源的子数据
* @param child
*/
void addChild(DataMergable child);

/**
* 获取标示数据源的唯一key
* @return
*/
String getKey();
}
SiteData实现接口实例,其它类同

public class SiteData implements DataMergable {
List<SitePageData> pages;

public void mergeFrom(DataMergable from) {
DataMergeUtil.merge(from, this);
}

public List<DataMergable> getChildren() {
List<DataMergable> result = new ArrayList<DataMergable>();
for (SitePageData page : pages) {
result.add(page);
}
return result;
}

public void setChildren(List<DataMergable> children) {
List<SitePageData> result = new ArrayList<SitePageData>();
for (DataMergable page : pages) {
result.add((SitePageData)page);
}
this.pages = result;
}

public void addChild(DataMergable child) {
this.addChild((SitePageData)child);
}

public String getKey() {
return this.getKey();
}
}

调用通用合并逻辑

public class DataMergeUtil {
public static void merge(DataMergable from, DataMergable to) {
// 判断是否需要合并
if (from != null && from.getChildren() != null && !from.getChildren().isEmpty()) {

// 如果要被合并的数据列表为空 , 则替换要合并过来的数据列表
if (to.getChildren() == null) {
to.setChildren(from.getChildren());
return;
}

// 要被合并的数据列表
List<DataMergable> mergeToDatas = to.getChildren();
// 要合并过来的数据列表
List<DataMergable> mergeFromDatas = from.getChildren();

// 构造一个map进行一一对应合并
Map<String, DataMergable> map = new HashMap<String, DataMergable>();
// 循环当前每个数据到map中
for (DataMergable dataTo : mergeToDatas) {
String key = dataTo.getKey();
map.put(key, dataTo);
}

// 循环每个要合并过来的每个数据, 一一对应地合并
for (DataMergable dataFrom : mergeFromDatas) {
String key = dataFrom.getKey();
DataMergable dataTo = map.get(key);
// 如果map中存在相同key的数据,则进行合并
if (dataTo != null) {
dataTo.mergeFrom(dataFrom);
// 如果map中不存在则直接添加来源的data
} else {
to.addChild(dataFrom);
}
}
}
}
}

优点

上面这种方案已经解决了面向过程及重复代码的问题

缺点

逻辑侵入了领域模型



第三种方案

同样是DataMergable接口不变

同时写一个通用逻辑实现此接口的类叫CommonDataMerge

为SiteData、SitePageData、SiteSegmentData、SiteRegionData、SiteAppData写个适配器用于实现DataMergable接口

public abstract class CommonDataMerge implements DataMergable {

/**
* 合并数据通用逻辑
*
* @param from 数据来源
*/
public void mergeFrom(DataMergable from) {

// 判断是否需要合并
if (from != null && from.getChildren() != null && !from.getChildren().isEmpty()) {

// 如果要被合并的数据列表为空 , 则替换要合并过来的数据列表
if (this.getChildren() == null) {
this.setChildren(from.getChildren());
return;
}

// 要被合并的数据列表
List<DataMergable> mergeToDatas = this.getChildren();
// 要合并过来的数据列表
List<DataMergable> mergeFromDatas = from.getChildren();

// 构造一个map进行一一对应合并
Map<String, DataMergable> map = new HashMap<String, DataMergable>();
// 循环当前每个数据到map中
for (DataMergable dataTo : mergeToDatas) {
String key = dataTo.getKey();
map.put(key, dataTo);
}

// 循环每个要合并过来的每个数据, 一一对应地合并
for (DataMergable dataFrom : mergeFromDatas) {
String key = dataFrom.getKey();
DataMergable dataTo = map.get(key);
// 如果map中存在相同key的数据,则进行合并
if (dataTo != null) {
dataTo.mergeFrom(dataFrom);
// 如果map中不存在则直接添加来源的data
} else {
this.addChild(dataFrom);
}
}
}

}

}
public class SiteDataMergeAdapter extends CommonDataMerge {
private SiteData data;
public SiteDataMergeAdapter(SiteData data){
super();
this.data = data;
}
@Override
public List<DataMergable> getChildren() {
List<DataMergable> children = new ArrayList<DataMergable>();
for (SitePageData sitePageData : data.getPages()) {
children.add(new SitePageDataMergeAdapter(sitePageData));
}
return children;
}

@Override
public void setChildren(List<DataMergable> children) {
List<SitePageData> list = new ArrayList<SitePageData>();
for (DataMergable dataMergable : children) {
list.add(((SitePageDataMergeAdapter) dataMergable).getData());
}
data.setPages(list);
}

@Override
public void addChild(DataMergable child) {
data.getPages().add(((SitePageDataMergeAdapter) child).getData());
}

@Override
public String getKey() {
return data.getSiteKey();
}

public SiteData getData() {
return data;
}
}

优点

合并代码不仅采用面向对象方法,抽象出合并的逻辑进行复用。并且无侵入原来的领域模型。可以把合并逻辑放在业务逻辑包,而不需要放到领域逻辑包里,从而解除了领域模型与数据合并的耦合代码。

使用了组合模式与适配器模式

缺点

多出几个类,并出现一些强制转换类型的代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值