`

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

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



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

站点数据(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;
    }
}

优点

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

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

缺点

多出几个类,并出现一些强制转换类型的代码
分享到:
评论

相关推荐

    23种设计模式--适配器模式

    在实际开发中,适配器模式与其他设计模式如装饰器模式、桥接模式等经常结合使用,以达到更好的效果。理解并熟练运用适配器模式,能帮助开发者解决接口不兼容的问题,提高代码的可维护性和可扩展性。

    Java设计模式适配器模式代码架构

    第三个例子展示了组合模式(Composite Pattern)和外观模式(Facade Pattern)的结合。`GeneralSwichFacade` 类提供了一个简单的接口来控制多个设备,包括灯、风扇、空调和电视。这种设计简化了客户端与多个复杂组件...

    设计模式之适配器模式(Adapter Pattern)

    通过使用适配器模式,我们可以使不兼容的系统之间实现协作,从而提高代码的可复用性和可维护性。在设计和实现时,需要注意适配器的设计应当尽可能简洁,以减少不必要的复杂度,并确保适配过程中的数据转换准确无误。...

    PHP设计模式之适配器模式原理与用法分析

    其中类适配器模式使用继承方式,而对象适配器模式使用组合方式。由于类适配器模式包含双重继承,而PHP并不支持双重继承,所以一般都采取结合继承和实现的方式来模拟双重继承,即继承一个类,同时实现一个接口。类...

    Head First 设计模式 (七) 适配器模式(Adapter pattern) C++实现

    命令模式和适配器模式可以结合使用,例如,适配器可以作为命令模式中的具体命令类,将其他系统的命令接口适配到我们自己的命令执行框架中。 总的来说,“Head First 设计模式”中对适配器模式的讲解,旨在帮助读者...

    2 适配器模式-课程内容.rar

    4. **对象适配器模式**:解释如何通过对象组合实现适配器,给出一个对象适配器模式的实例,比较与类适配器的区别。 5. **适配器模式的应用场景**:列出适配器模式常见的应用,如旧系统的接口兼容、不同硬件设备的...

    适配器模式和桥接模式共26页.pdf.zip

    在实际编程中,适配器模式和桥接模式经常被结合使用,特别是在处理复杂系统集成和框架扩展时。了解并熟练掌握这两种模式,对于提升软件设计的质量和灵活性至关重要。在阅读"适配器模式和桥接模式共26页.pdf"这份资料...

    23种设计模式项目实例

    结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、...

    24种设计模式以及混合设计模式

    其中包括代理模式(Proxy)、装饰器模式(Decorator)、适配器模式(Adapter)、桥接模式(Bridge)、组合模式(Composite)、外观模式(Facade)和享元模式(Flyweight)。这些模式帮助我们在不修改原有代码的情况...

    java 设计模式之适配器模式的详解

    Java 设计模式之适配器模式的详解 适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的接口,使得...因此,在使用适配器模式时,需要仔细考虑实际情况,选择合适的解决方案。

    PHP设计模式之适配器模式定义与用法详解

    通过以上分析,适配器模式在实际开发中,尤其是当需要将一个旧系统与新系统结合,或者需要对系统提供更加灵活的接口时,其重要性和实用性都得到了体现。适配器模式通过增加一层适配逻辑,避免了对原有系统的大幅修改...

    java与模式光盘源码

    例如,组合模式(Composite)结合了部分与整体的行为,使得代码能够一致地处理单个对象和对象集合。桥接模式(Bridge)将抽象部分与其实现部分分离,使它们可以独立变化,提供更大的灵活性。这些模式的组合使用可以...

    Java与模式(闫宏)

    2. 结构型模式:适配器模式、装饰器模式、代理模式、桥接模式、组合模式、外观模式、享元模式。这些模式主要处理类和对象之间的关系,提高代码的可扩展性和模块化。 3. 行为型模式:策略模式、模板方法模式、观察者...

    设计模式之美——教你写出高质量代码

    2. 结构型模式:如适配器模式、装饰器模式、代理模式、桥接模式、组合模式、外观模式和享元模式。这些模式关注的是如何将类或对象结合在一起形成更大的结构,同时保持它们之间的松耦合。 3. 行为型模式:如策略模式...

    C#面向对象设计模式纵横谈 12种设计模式

    本篇将深入探讨12种核心的设计模式,它们是:单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式、适配器模式、装饰器模式、代理模式、桥接模式、组合模式、享元模式和观察者模式。 1. **单例模式**:确保一...

    Head First 设计模式学习笔记(十四)模式的组合使用

    2. **组合模式(Composite Pattern)**:Flock.java文件可能代表了组合模式的应用,该模式将对象组合成树形结构以表示部分-整体的层次关系。Flock类可能作为一个容器,持有多个Duck对象,实现了整体行为,如让整个鸭...

    设计模式之结构型模式uml类图EA文件.rar

    下面我们将详细探讨其中涉及到的几个模式:桥接模式、适配器模式、装饰者模式和组合模式,并结合UML类图和EA(Enterprise Architect)文件来理解它们。 1. **桥接模式**:桥接模式是一种将抽象部分与实现部分分离的...

    java与模式-阎宏

    3. 结构型模式:包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。这些模式关注于如何组织类和对象,以提高系统的灵活性和可扩展性。 4. 行为型模式:包括职责链模式、命令模式、解释...

    重学java的设计模式

    结构型模式包括适配器模式、装饰器模式、代理模式、桥接模式、组合模式、外观模式和享元模式。这些模式有助于在不修改原有代码的基础上增加新的功能,或者在不同组件之间建立松散耦合。 1. 适配器模式:将两个不...

Global site tag (gtag.js) - Google Analytics