设计模式--组合模式真实案例

所有的例子均来源与实际开发项目

本节介绍组合模式的使用–商品结果排序评分系统

首先还是重复一下:设计模式是思路,而不是一味套用,如果业务场景和功能需求恰好吻合,那最好不过;如果有偏差,一定要具体情况具体分析,更具实际场景选择合适的模式类型(注意,是类型,并不特定指某种模式,有的时候一个场景多种模式都可以做)



本节所举得例子为商品结果排序评分系统,也就是很多项目中,在比较重要任何事物查询完毕后,会有一个排序过程,比如在淘宝上搜索完商品后那个商品列表的排序过程。而且其复杂度当然远远超过数据中SQL语句可以完成的程度(当然不排除有公司把逻辑直接写入到存储过程中,但是这种情况不做探讨),所以需要一个完整的评分系统来对结果进行排序,高分排前,低分置后。

Ⅰ 【分析阶段】———————————

a.首先分析业务功能(功能需求):类似于上面所述的,就是对结果进行排序,高分前,低分后。再深入到实现代码层面,就是多层次的权重分数计算了,这个类似大家学校里,最终期末总评分,30%平时分,70%考试分一个道理;

b.然后分析扩展性(非功能需求):主要变化会在哪?当然毫无疑问就是:

  • 评分的权重会发生变化:之前占80%的比例,现在被削弱了,只占20%了;
  • 评分的相互层次关系可能变化:之前这个评分是最低一级的了,现在在它下面又多了两级更细化的评分;
  • 乃至评分的逻辑处理会发生变化…

好了,结合上面两点,你会发现,这有点一个“树”的意思了,不是么?请看下面这个图

左边一个一般的树图,类似资源管理器的列表单,这个摘自《研磨设计模式》P392页的组合模式章节配图

右边是我刚刚所说的业务功能的分析图,一个商品的综合总评分分为“商品评分”与发布该商品的“店铺评分”,分别占总评分的80%与20%,然后其下面又分别有子评分标准,以此类推,图片应该不难理解

这个时候,当然需要你对组合模式还是有了了解,至少要有印象,知道有这么一个模式可以作为备选,然后一比较,发现确实也凑巧,这个例子非常符合组合模式,而且看起来至少目前不需要做太大改动,已经可以满足需求了。那就开始设计吧!



Ⅱ【设计阶段】——————————————————-

类图设计如下,以下图片中上半部分摘自《研磨设计模式》P396 图15.1 ,下面为我基于他的图进行的部分修改,即为我的组合模式的设计

是不是发现还是变化了不少,这就是我之前在第一篇文章设计模式–概述【请看清本质】中所提到的观点,不用在乎一些改变,而要关注设计模式的核心目标是否达到

好了,继续对上面的设计做一些说明:

身份对应:

  • ScoreCalculator —-对应—> Component,只是在原来书中例子,component为接口,我这里进一步改为了一个抽象类,因为其中还嵌入了一个模板模式的做法,我在代码中会有说明;
  • XXScoreCalculator — 对应 —> Composite , 其实就是具体的实现类了
  • Leaf —- > ?? 在这里,我删去了Leaf这个角色,为什么?因为在书中例子里,Leaf作为叶子节点,即树结构的最末端节点是不会有“子节点”存在的,所以设置了这一角色,但是我这里由于各种计算分数的规则在将来随时可能由于业务的变更会要产生子节点,这样就不可能把任何一个分数计算规则指定为“无子节点”的类型,所以我索性去掉了Leaf角色

具体实现,我结合代码示例进行说明:

/**
* 评分计算基类
* 这里我略掉了一些什么addChild,removeChild等方法的说明,这个大家需要自行加入
*/
public abstract class ScoreCalculator {

    // list用于存放子类
    // 至于我这里为什么还封装到了一个Entry里,只是完全出于业务考虑,因为既要放规则计算类,又要放入配置文件导入的权重参数
    // 像这个就需要大家根据自己业务灵活处理
    protected List scoreEntryList;

    public int calculateScore(){

        int totalScore = 0;

        //先进行子节点的分数计算,对叶子节点来说,由于没有子节点,这个代码段就自然不会执行了
        if(this.scoreEntryList!=null){
            int[] scoreArray = new int[scoreEntryList.size()];
            ScoreEntry entry = null;
            for (int i =0; i < scoreEntryList.size(); i++) {
                entry = scoreEntryList.get(i);
                //这里调用子节点的calculateScore(),递归!,也就是组合模式的核心思想之一
                scoreArray[i] = (int)(Math.round(entry.cal.calculateScore() * entry.weight));
                totalScore += scoreArray[i];
            }
        }

        //注意,这里就用了模板方法的思想,上面所做的一切都是不变的,就是计算子节点的分数然后汇总
        //那统计完子节点的了,自己还要进一步做处理吧?毕竟有些简单的加减乘除就解决了,有些可还有复杂的逻辑
        totalScore = moreCalculate(totalScore);
        return totalScore;
    }

    //抽象方法,让子类自己去实现
    protected abstract int moreCalculate(int currentTotalScore);

}

public class ScoreEntry {
    //规则计算类
    public ScoreCalculator cal;
    //本规则在上一级规则中所占的比重(0~1)
    public float weight;
    //本规则在计算后的结果,整型(0~10000)
    public int score;
}

对于具体的实现类来说,就比较清晰了,实现该实现的方法就好了

/*
* 店铺分数计算规则,其还带有子类规则A1,A2
* 至于商品分数计算规则的思路就差不多了,这里就只举此一个
*/
public class ShopCalculator extends ScoreCalculator {

    //..构造方法等等略

    @Override
    protected int moreCalculate(int currentTotalScore) {

        //进行具体的操作,比如这些分数还要进一步结合店铺的某种其他信息做检查处理
        //然后做相应的增减,最后返回数据至上一层,向上一层统计分数节点“呈递”自己的最终结果
        currentTotalScore = doSth();

        return currentTotalScore;
    }
}

不知道大家是否能够顺利理解,毕竟这个例子是实际项目,逻辑相对复杂,篇幅问题我也只能选择核心代码给出,所以难免会看着有点困难,没关系,重点看我有注释的那几行便可,若有问题可以回帖发问~

好了,继续还有一点收尾,那既然这棵树“种好了”,那怎么来使用呢?设计模式不仅仅要便于扩展,也要便于使用,那我们就来看看如何搭建起这个树结构,也就是上面画图中,那个Client怎么调用了

//首先提醒一句,大家在看上面第二幅图时,《研磨设计模式》书中图里有addChild方法,怎么样?想到了怎么建立树了吗?
//对吧,其实很简单,new出节点,然后通过addChild建立起双方的父子关系便可了

//总分统计
ScoreCalculator totalCal = new TotalCalculator();
//商品统计,数字是在上级中的所占权重
ScoreCalculator goodsCal = new GoodsCalculator(0.8);
//店铺统计
ScoreCalculator shopCal = new ShopCalculator(0.2);
//A1统计
ScoreCalculator a1Cal = new A1Calculator(0.3);
//A2统计
ScoreCalculator a2Cal = new A2Calculator(0.7);
...(略)

//好了,把相互的关系整理起来!
goodsCal.addChild(a1Cal);
goodsCal.addChild(a2Cal);
...
totalCal.addChild(goodsCal);
totalCal.addChild(shopCal);

//最后,执行计算就OK了!无穷的递归就在这一刻开始
int finalScore = totalCal.calculateScore();

Ⅲ【核查阶段】———————————————————–

好了,到这里为止,这个样例算是分析完了,只是还查了一点,什么呢?检查!

就是检查这个最终的开发结果是不是达到的之前的设计目的:

  • 业务功能是否满足?当然满足了,是按照权重计算,分层递归网上走,层层按权重统计汇总,最终出总结果
  • 扩展性是否良好?没问题,当有新的规则出现时,创建一个新的继承自ScoreCalculator的类,然后实现moreCalculator方法进行自身逻辑处理即可;
  • 能否处理业务变化?首先,每个规则之间业务处理完全分开,权重修改加个个配置文件即可搞定,变更修改不会对其他业务构成影响;然后当有节点层次关系发生变化时,在Client调用中进行变更child层次结构即可

可见,目的都算是达到了,这个模式的使用就算是合格了!

在这里,大家发现我其中用上了模板模式,其实在这个以组合模式为核心的模块里里外外还包围着很多其他模式来进行辅助,这里我为了避免影响都没有写出来了,有点像变形金刚合体一样。这依旧说明了一点:

模式为思想,方法不固定,灵活变通使用才是硬道理!

欢迎访问我的主页,最新的文章我会首先发布在个人主页上:

http://blog.guaidm.com/shocky

设计模式--组合模式真实案例,布布扣,bubuko.com

时间: 2024-08-01 22:39:03

设计模式--组合模式真实案例的相关文章

16. 星际争霸之php设计模式--组合模式

题记==============================================================================本php设计模式专辑来源于博客(jymoz.com),现在已经访问不了了,这一系列文章是我找了很久才找到完整的,感谢作者jymoz的辛苦付出哦! 本文地址:http://www.cnblogs.com/davidhhuan/p/4248201.html============================================

设计模式 - 组合模式(composite pattern) 详解

组合模式(composite pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy 组合模式: 允许你将对象组合成树形结构来表现"整体/部分"层次结构. 组合能让客户以一致的方法处理个别对象以及组合对象. 建立组件类(Component), 组合类(composite)和叶子类(leaf)继承组件类, 客户类(client)直接调用最顶层的组合类(composite)即可. 具体方法: 1. 组件类(component), 包含组合

数据库学习设计模式--组合模式

介绍: 想必你已经了解了数据结构中的树,ok,组合模式对于你就是一会儿的功夫了.组合模式相对来说比较简单.看一下定义 abstract class Component { protected String name; //这个用来标示一下节点 public Component(String name) { this.name = name; } public abstract void add(Component c);//增加儿子节点 public abstract void remove(C

设计模式 - 组合模式(composite pattern) 迭代器(iterator) 详解

组合模式(composite pattern) 迭代器(iterator) 详解 本文地址: http://blog.csdn.net/caroline_wendy 参考组合模式(composite pattern): http://blog.csdn.net/caroline_wendy/article/details/36895627 在组合模式(composite pattern)添加迭代器功能, 遍历每一个组合(composite)的项. 具体方法: 1. 抽象组件类(abstract

跟着ZHONGHuan学习设计模式--组合模式

跟着ZHONGHuan学习设计模式 组合模式 介绍: 想必你已经了解了数据结构中的树,ok,组合模式对于你就是一会儿的功夫了.组合模式相对来说比较简单.看一下定义 组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构.使得用户对单个对象和组合对象的使用具有一致性. 暂时没有想到好的例子,如果你有,请告诉我.下面我用树来对组合模式进行解释.树的结构是下面的这样的: 没棵树有一个根节点,也有叶子节点和树枝节点,一些结构都是用树结构表示的,例如树形菜单,文件和文件夹目录.那么如何存储管理这样的

设计模式之禅之设计模式-组合模式

一:组合模式的定义        --->组合模式(Composite Pattern)也叫合成模式,有时又叫做部分-整体模式(Part-Whole),主要是用来描述部分与整体的关系        --->将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性. 二:组合模式的角色        ● Component抽象构件角色                定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性        ● Leaf叶

说说设计模式~组合模式(Composite)

返回目录 何时能用到它? 组合模式又叫部分-整体模式,在树型结构中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦.对于今天这个例子来说,它可以很清楚的说明组合模式的用意,首先是一个Graphics对象,它表示是一绘图功能(树根),而circle,line和rectangle分别是简单的图形,它们内部不能再有其它图形了(相当于树叶),而picture是一个复杂图形,它由circle,line和rectangle组成(相当于树

5分钟读书笔记之 - 设计模式 - 组合模式

组合模式是一种专为创建Web上的动态用户界面而量身定制的模式,使用这种模式,可以用一条命令在对各对象上激发复杂的或递归的行为. 在组合对象的层次体系中有俩种类型对象:叶对象和组合对象.这是一个递归定义,但这正是组合模式如此有用的原因所在.一个组合对象由一些别的组合对象和叶对象组成,其中只有叶对象不再包含子对象,叶对象是组合对象中最基本的元素,也是各种操作的落实地点. 存在一批组织成某种层次体系的对象(具体的结构在开发期间可能无法得知) 希望这批对象或其中的一部分对象实施一个操作 表单验证实例:

设计模式 -- 组合模式(Composite)

写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------主要内容包括: 初识组合模式,包括:定义.结构.参考实现 体会组合模式,包括:场景问题.不用模式的解决方案.使用模式的解决方案 理解组合模式,包括:认识组合模式.安全性和透明性.父组件引用.环状引用.组合模式的优缺点 思考组合模式,包括:组合模式的本质.何时选用 参考内容: 1.<研磨设计模式> 一书,作者:陈臣.王斌 --