Welcome

首页 / 软件开发 / 数据结构与算法 / Ruby设计模式透析:组合(Composite)

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

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

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

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

def get_novels_browse_countbrowse_count = 0all_novels = get_all_novels()all_novels.each do |novel|browse_count += get_browse_count(novel)endbrowse_countenddef get_novels_sale_countsale_count = 0all_novels = get_all_novels()all_novels.each do |novel|sale_count += get_browse_count(novel)endsale_countend
很快你就写下了以上两个方法,这两个方法都是通过获取到所有的小说名,然后一一计算 每本小说的浏览量和销售量,最后将结果相加得到总量。

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

def get_computer_books_browse_countbrowse_count = 0all_computer_books = get_all_computer_books()all_computer_books.each do |computer_book|browse_count += get_browse_count(computer_book)endbrowse_countenddef get_computer_books_sale_countsale_count = 0all_computer_books = get_all_computer_books()all_computer_books.each do |computer_book|sale_count += get_browse_count(computer_book)endsale_countend
除了使用了get_all_computer_books方法获取到所有的计算机类书名,其它的代码基本和 小说统计中的是一样的。

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

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

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

class Statisticsdef get_browse_countraise "You should override this method in subclass."enddef get_sale_countraise "You should override this method in subclass."endend
这两个方法都是简单地抛出一个异常,因为需要在子类中重写这两个方法。

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

class NovelStatistics < Statisticsdef get_browse_countbrowse_count = 0all_novels = get_all_novels()all_novels.each do |novel|browse_count += get_browse_count(novel)endbrowse_countenddef get_sale_countsale_count = 0all_novels = get_all_novels()all_novels.each do |novel|sale_count += get_browse_count(novel)endsale_countendend