- 浏览: 21920 次
- 性别:
- 来自: 厦门
文章分类
最新评论
模板模式与适配器模式组合使用之合并站点数据
考虑一下这样的一个场景,网站模板应用到网站时需要合并站点数据。
站点数据(SiteData)是由页面(SitePageData)组成的,页面是由页面片段(SiteSegmentData)组成的,页面片段是由区域(SiteRegionData)组成的,区域是由版块(SiteAppData)组成的。
第一方案
优点
思路清晰,
缺点
面向过程,合并过程逻辑十分相似,可以认为是重复代码。
第二方案
从上面方案中总结出来,需要面向对象,于是我认为数据具备合并功能,在SiteData、SitePageData、SiteSegmentData、SiteRegionData、SiteAppData类去实现合并接口DataMergeable。
调用通用合并逻辑
优点
上面这种方案已经解决了面向过程及重复代码的问题
缺点
逻辑侵入了领域模型
第三种方案
同样是DataMergable接口不变
同时写一个通用逻辑实现此接口的类叫CommonDataMerge
为SiteData、SitePageData、SiteSegmentData、SiteRegionData、SiteAppData写个适配器用于实现DataMergable接口
优点
合并代码不仅采用面向对象方法,抽象出合并的逻辑进行复用。并且无侵入原来的领域模型。可以把合并逻辑放在业务逻辑包,而不需要放到领域逻辑包里,从而解除了领域模型与数据合并的耦合代码。
使用了组合模式与适配器模式
缺点
多出几个类,并出现一些强制转换类型的代码
考虑一下这样的一个场景,网站模板应用到网站时需要合并站点数据。
站点数据(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; } }
优点
合并代码不仅采用面向对象方法,抽象出合并的逻辑进行复用。并且无侵入原来的领域模型。可以把合并逻辑放在业务逻辑包,而不需要放到领域逻辑包里,从而解除了领域模型与数据合并的耦合代码。
使用了组合模式与适配器模式
缺点
多出几个类,并出现一些强制转换类型的代码
相关推荐
在实际开发中,适配器模式与其他设计模式如装饰器模式、桥接模式等经常结合使用,以达到更好的效果。理解并熟练运用适配器模式,能帮助开发者解决接口不兼容的问题,提高代码的可维护性和可扩展性。
第三个例子展示了组合模式(Composite Pattern)和外观模式(Facade Pattern)的结合。`GeneralSwichFacade` 类提供了一个简单的接口来控制多个设备,包括灯、风扇、空调和电视。这种设计简化了客户端与多个复杂组件...
通过使用适配器模式,我们可以使不兼容的系统之间实现协作,从而提高代码的可复用性和可维护性。在设计和实现时,需要注意适配器的设计应当尽可能简洁,以减少不必要的复杂度,并确保适配过程中的数据转换准确无误。...
其中类适配器模式使用继承方式,而对象适配器模式使用组合方式。由于类适配器模式包含双重继承,而PHP并不支持双重继承,所以一般都采取结合继承和实现的方式来模拟双重继承,即继承一个类,同时实现一个接口。类...
命令模式和适配器模式可以结合使用,例如,适配器可以作为命令模式中的具体命令类,将其他系统的命令接口适配到我们自己的命令执行框架中。 总的来说,“Head First 设计模式”中对适配器模式的讲解,旨在帮助读者...
4. **对象适配器模式**:解释如何通过对象组合实现适配器,给出一个对象适配器模式的实例,比较与类适配器的区别。 5. **适配器模式的应用场景**:列出适配器模式常见的应用,如旧系统的接口兼容、不同硬件设备的...
在实际编程中,适配器模式和桥接模式经常被结合使用,特别是在处理复杂系统集成和框架扩展时。了解并熟练掌握这两种模式,对于提升软件设计的质量和灵活性至关重要。在阅读"适配器模式和桥接模式共26页.pdf"这份资料...
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、...
其中包括代理模式(Proxy)、装饰器模式(Decorator)、适配器模式(Adapter)、桥接模式(Bridge)、组合模式(Composite)、外观模式(Facade)和享元模式(Flyweight)。这些模式帮助我们在不修改原有代码的情况...
Java 设计模式之适配器模式的详解 适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的接口,使得...因此,在使用适配器模式时,需要仔细考虑实际情况,选择合适的解决方案。
通过以上分析,适配器模式在实际开发中,尤其是当需要将一个旧系统与新系统结合,或者需要对系统提供更加灵活的接口时,其重要性和实用性都得到了体现。适配器模式通过增加一层适配逻辑,避免了对原有系统的大幅修改...
例如,组合模式(Composite)结合了部分与整体的行为,使得代码能够一致地处理单个对象和对象集合。桥接模式(Bridge)将抽象部分与其实现部分分离,使它们可以独立变化,提供更大的灵活性。这些模式的组合使用可以...
2. 结构型模式:适配器模式、装饰器模式、代理模式、桥接模式、组合模式、外观模式、享元模式。这些模式主要处理类和对象之间的关系,提高代码的可扩展性和模块化。 3. 行为型模式:策略模式、模板方法模式、观察者...
2. 结构型模式:如适配器模式、装饰器模式、代理模式、桥接模式、组合模式、外观模式和享元模式。这些模式关注的是如何将类或对象结合在一起形成更大的结构,同时保持它们之间的松耦合。 3. 行为型模式:如策略模式...
本篇将深入探讨12种核心的设计模式,它们是:单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式、适配器模式、装饰器模式、代理模式、桥接模式、组合模式、享元模式和观察者模式。 1. **单例模式**:确保一...
2. **组合模式(Composite Pattern)**:Flock.java文件可能代表了组合模式的应用,该模式将对象组合成树形结构以表示部分-整体的层次关系。Flock类可能作为一个容器,持有多个Duck对象,实现了整体行为,如让整个鸭...
下面我们将详细探讨其中涉及到的几个模式:桥接模式、适配器模式、装饰者模式和组合模式,并结合UML类图和EA(Enterprise Architect)文件来理解它们。 1. **桥接模式**:桥接模式是一种将抽象部分与实现部分分离的...
3. 结构型模式:包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。这些模式关注于如何组织类和对象,以提高系统的灵活性和可扩展性。 4. 行为型模式:包括职责链模式、命令模式、解释...
结构型模式包括适配器模式、装饰器模式、代理模式、桥接模式、组合模式、外观模式和享元模式。这些模式有助于在不修改原有代码的基础上增加新的功能,或者在不同组件之间建立松散耦合。 1. 适配器模式:将两个不...