详解组合模式的结构及其在Ruby设计模式编程中的运用
定义:也叫合成模式,或者部分-整体模式,主要是用来描述部分与整体的关系,定义,将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。 类图: 角色说明: Componnent抽象构件角色:定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性。 实例: 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方法获取到所有的计算机类书名,其它的代码基本和小说统计中的是一样的。 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 这两个方法都是简单地抛出一个异常,因为需要在子类中重写这两个方法。 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方法中遍历所有的子分类,计算出它们各自的浏览量和销售量,然后相加得到总额返回。 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 当然你后面还可以对这个组合结构随意地改变,添加各种子分类书籍,而且子分类的层次结构可以任意深,正如前面所说,组合模式的扩展性非常好。 总结 组合模式的优点: 组合模式的缺点: 组合模式的适用场景: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |