转载请注明出处:http://blog.csdn.net/sinyu890807/article/details/9153761

此为Java设计模式透析的拷贝版,专门为Ruby爱好者提供的,不熟悉Ruby语法的朋友请转阅 :

Java设计模式透析之 —— 组合(Composite)

听说你们公司最近新推出了一款电子书阅读应用,市场反应很不错,应用里还有图书商城,用户可以在其中随意选购自己喜欢的书籍。你们公司也是对此项目高度重视,加大了投入力度,决定给此应用再增加点功能。

好吧,你也知道你是逃不过此劫了,没过多久你的leader就找到了你。他告诉你目前的应用对每本书的浏览量和销售量做了统计,但现在想增加对每个书籍分类的浏览量和销售量以及所有书籍总的浏览量和销售量做统计的功能,希望你可以来完成这项功能。

领导安排的工作当然是推脱不掉的,你只能硬着头皮上了,不过好在这个功能看起来也不怎么复杂。

你比较喜欢看小说,那么就从小说类的统计功能开始做起吧。首先通过get_all_novels方法可以获取到所有的小说名,然后将小说名传入get_browse_count方法可以得到该书的浏览量,将小说名传入get_sale_count方法可以得到该书的销售量。你目前只有这几个已知的API可以使用,那么开始动手吧!

def get_novels_browse_count
browse_count = 0
all_novels = get_all_novels()
all_novels.each do |novel|
browse_count += get_browse_count(novel)
end
browse_count
end def get_novels_sale_count
sale_count = 0
all_novels = get_all_novels()
all_novels.each do |novel|
sale_count += get_browse_count(novel)
end
sale_count
end

很快你就写下了以上两个方法,这两个方法都是通过获取到所有的小说名,然后一一计算每本小说的浏览量和销售量,最后将结果相加得到总量。

小说类的统计就完成了,然后你开始做计算机类书籍的统计功能,代码如下所示:

def get_computer_books_browse_count
browse_count = 0
all_computer_books = get_all_computer_books()
all_computer_books.each do |computer_book|
browse_count += get_browse_count(computer_book)
end
browse_count
end def get_computer_books_sale_count
sale_count = 0
all_computer_books = get_all_computer_books()
all_computer_books.each do |computer_book|
sale_count += get_browse_count(computer_book)
end
sale_count
end

除了使用了get_all_computer_books方法获取到所有的计算机类书名,其它的代码基本和小说统计中的是一样的。

现在你才完成了两类书籍的统计功能,后面还有医学类、自然类、历史类、法律类、政治类、哲学类、旅游类、美食类等等等等书籍。你突然意识到了一些问题的严重性,工作量大倒还不算什么,但再这么写下去,你的方法就要爆炸了,这么多的方法让人看都看不过来,别提怎么使用了。

这个时候你只好向你的leader求助了,跟他说明了你的困惑。只见你的leader思考了片刻,然后自信地告诉你,使用组合模式不仅可以轻松消除你的困惑,还能出色地完成功能。

他立刻向你秀起了编码操作,首先定义一个Statistics类,里面有两个方法:

class Statistics

	def get_browse_count
raise "You should override this method in subclass."
end def get_sale_count
raise "You should override this method in subclass."
end end

这两个方法都是简单地抛出一个异常,因为需要在子类中重写这两个方法。

然后定义一个用于统计小说类书籍的NovelStatistics类,继承刚刚定义的Statistics类,并重写Statistics中的两个方法:

class NovelStatistics < Statistics

	def get_browse_count
browse_count = 0
all_novels = get_all_novels()
all_novels.each do |novel|
browse_count += get_browse_count(novel)
end
browse_count
end def get_sale_count
sale_count = 0
all_novels = get_all_novels()
all_novels.each do |novel|
sale_count += get_browse_count(novel)
end
sale_count
end end

在这两个方法中分别统计了小说类书籍的浏览量和销售量。那么同样的方法,你的leader又定义了一个ComputerBookStatistics类用于统计计算机类书籍的浏览量和销售量:

class ComputerBookStatistics < Statistics

	def get_browse_count
browse_count = 0
all_computer_books = get_all_computer_books()
all_computer_books.each do |computer_book|
browse_count += get_browse_count(computer_book)
end
browse_count
end def get_sale_count
sale_count = 0
all_computer_books = get_all_computer_books()
all_computer_books.each do |computer_book|
sale_count += get_browse_count(computer_book)
end
sale_count
end end

这样将具体的统计实现分散在各个类中,就不会再出现你刚刚那种方法爆炸的情况了。不过这还没开始真正使用组合模式呢,好戏还在后头,你的leader吹嘘道。

再定义一个MedicalBookStatistics类继承Statistics,用于统计医学类书籍的浏览量和销售量,代码如下如示:

class MedicalBookStatistics < Statistics

	def get_browse_count
browse_count = 0
all_medical_books = get_all_medical_books()
all_medical_books.each do |medical_book|
browse_count += get_browse_count(medical_book)
end
browse_count
end def get_sale_count
sale_count = 0
all_medical_books = get_all_medical_books()
all_medical_books.each do |medical_book|
sale_count += get_browse_count(medical_book)
end
sale_count
end end

不知道你发现了没有,计算机类书籍和医学类书籍其实都算是科技类书籍,它们是可以组合在一起的。这个时候你的leader定义了一个TechnicalStatistics类用于对科技这一组合类书籍进行统计:

class TechnicalStatistics < Statistics

	def initialize
@statistics = []
@statistics << ComputerBookStatistics.new
@statistics << MedicalBookStatistics.new
end def get_browse_count
browse_count = 0
@statistics.each do |s|
browse_count += s.get_browse_count
end
browse_count
end def get_sale_count
sale_count = 0
@statistics.each do |s|
sale_count += s.get_sale_count
end
sale_count
end end

可以看到,由于这个类是组合类,和前面几个类还是有不少区别的。首先TechnicalStatistics中有一个构造函数,在构造函数中将计算机类书籍和医学类书籍作为子分类添加到statistics数组当中,然后分别在get_browse_count和get_sale_count方法中遍历所有的子分类,计算出它们各自的浏览量和销售量,然后相加得到总额返回。

组合模式的扩展性非常好,没有各种条条框框,想怎么组合就怎么组合,比如所有书籍就是由各个分类组合而来的,你的leader马上又向你炫耀了统计所有书籍的浏览量和销售量的办法。

定义一个AllStatistics类继承Statistics,具体代码如下所示:

class AllStatistics < Statistics

	def initialize
@statistics = []
@statistics << NovelStatistics.new
@statistics << TechnicalStatistics.new
end def get_browse_count
browse_count = 0
@statistics.each do |s|
browse_count += s.get_browse_count
end
browse_count
end def get_sale_count
sale_count = 0
@statistics.each do |s|
sale_count += s.get_sale_count
end
sale_count
end end

在AllStatistics的构造函数中将小说类书籍和科技类书籍作为子分类添加到了statistics数组当中,目前你也就只写好了这几个分类。然后使用同样的方法在get_browse_count和get_sale_count方法中统计出所有书籍的浏览量和销售量。

当前组合结构的示意图如下:

现在你就可以非常方便的得到任何分类书籍的浏览量和销售量了,比如说获取科技类书籍的浏览量,你只需要调用:

TechnicalStatistics.new.get_browse_count

而获取所有书籍的总销量,你只需要调用:

AllStatistics.new.get_sale_count

当然你后面还可以对这个组合结构随意地改变,添加各种子分类书籍,而且子分类的层次结构可以任意深,正如前面所说,组合模式的扩展性非常好。

你的leader告诉你,目前他写的这份代码重复度比较高,其实还可以好好优化一下的,把冗余代码都去除掉。当然这个任务就交给你来做了,你的leader可是大忙人,早就一溜烟跑开了。

组合:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

Ruby设计模式透析之 —— 组合(Composite)的更多相关文章

  1. Java设计模式透析之 —— 组合(Composite)

    听说你们公司最近新推出了一款电子书阅读应用,市场反应很不错,应用里还有图书商城,用户可以在其中随意选购自己喜欢的书籍.你们公司也是对此项目高度重视,加大了投入力度,决定给此应用再增加点功能. 好吧,你 ...

  2. Ruby设计模式透析之 —— 适配器(Adapter)

    转载请注明出处:http://blog.csdn.net/sinyu890807/article/details/9400153 此为Java设计模式透析的拷贝版,专门为Ruby爱好者提供的,不熟悉R ...

  3. 设计模式C++描述----11.组合(Composite)模式

    一. 举例 这个例子是书上的,假设有一个公司的组结结构如下: 它的结构很像一棵树,其中人力资源部和财务部是没有子结点的,具体公司才有子结点. 而且最关健的是,它的每一层结构很相似. 代码实现如下: / ...

  4. Java设计模式透析之 —— 单例(Singleton)

    写软件的时候经常需要用到打印日志功能,可以帮助你调试和定位问题,项目上线后还可以帮助你分析数据.但是Java原生带有的System.out.println()方法却很少在真正的项目开发中使用,甚至像f ...

  5. Java设计模式透析之 —— 适配器(Adapter)

    转载请注明出处:http://blog.csdn.net/sinyu890807/article/details/9400141 今天一大早,你的leader就匆匆忙忙跑过来找到你:“快,快,紧急任务 ...

  6. Java设计模式透析之 —— 策略(Strategy)

    今天你的leader兴致冲冲地找到你,希望你能够帮他一个小忙.他如今急着要去开会.要帮什么忙呢?你非常好奇. 他对你说.当前你们项目的数据库中有一张用户信息表.里面存放了非常用户的数据.如今须要完毕一 ...

  7. Java设计模式透析之 —— 模板方法(Template Method)

    今天你还是像往常一样来上班,一如既往地開始了你的编程工作. 项目经理告诉你,今天想在server端添加一个新功能.希望写一个方法.能对Book对象进行处理.将Book对象的全部字段以XML格式进行包装 ...

  8. 设计模式(十)组合模式(Composite Pattern)

    一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象 ...

  9. 设计模式(七)组合模式Composite(结构型)

    设计模式(七)组合模式Composite(结构型) 1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 ...

随机推荐

  1. 一步一步写算法(之prim算法 中)

    原文:一步一步写算法(之prim算法 中) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] C)编写最小生成树,涉及创建.挑选和添加过程 MI ...

  2. javascript1

    <script> //初始化表达式:通过方括号定义数组元素和通过花括号定义对象属性名和属性值之间的映射关系的语法 //通过“.”和“[]”来引用对象属性或数组元素的值就构成一个表达式. v ...

  3. PHP 12 :字符串的操作

    原文:PHP 12 :字符串的操作 本章介绍字符串的操作.之所以要把字符串单独拿出来讲,是因为字符串在每种语言里都是非常重要的.并且也是大家关心的.我们从以下几个方面介绍字符串: 字符串的表现形式. ...

  4. [译]Java 垃圾回收介绍

    说明:这篇文章来翻译来自于Javapapers 的Java Garbage Collection Introduction 在Java中,对象内存空间的分配与回收是由JVM中的垃圾回收进程自动完成的. ...

  5. ubuntu下的词典的安装

    因为从事开发,安装一个词典是很有必要,文中介绍安装openyoudao和stardic两个软件的方法 一.openyoudao的安装 因为是由window转来学ubuntu的,所以总是想安装和wind ...

  6. Android-异步图像装载机

    在ListView加载图像是非常常见的场景,图像加载几个要求满足以下的: (1)是否画面位于网络或本地上,装载不应同步.但应该异步加载,例如,使用AsyncTask. (2)为了避免重复下载图片和网页 ...

  7. 【WebSocket初探 】

    众所周知,socket是编写网络通信应用的基本技术,网络数据交换大多直接或间接通过socket进行.对于直接使用socket的client与服务端,一旦连接被建立则均可主动向对方传送数据,而对于使用更 ...

  8. 删除指定表的所有索引,包括主键索引,唯一索引和普通索引 ,适用于sql server 2005,

    原文:删除指定表的所有索引,包括主键索引,唯一索引和普通索引 ,适用于sql server 2005, --删除指定表中所有索引 --用法:declare @tableName varchar(100 ...

  9. .Net组件程序设计

    .Net组件程序设计之上下文 在后续篇幅的远程调用的文章里有说到应用程序域,那是大粒度的控制程序集的逻辑存在,那么想对对象的控制又由谁来做主呢?没错了,就是上下文.CLR把应用程序域更细化了,在应用程 ...

  10. MVC程序中实体框架的连接恢复和命令拦截

    MVC程序中实体框架的连接恢复和命令拦截 这是微软官方SignalR 2.0教程Getting Started with Entity Framework 6 Code First using MVC ...