完整指南组合模式的结构及其在Ruby设计模式编程中的运用
平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“详细解析组合模式的结构及其在Ruby设计模式编程中的运用”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。
定义:从实现思路看,也叫合成模式,或者部分-整体模式,主要是用来描述部分与整体的关系,定义,将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的采用具有一致性。
类图:
角色说明:
理解这一步时,Componnent抽象构件角色:定义参加组合对象的共有方法和属性,能够定义一些默认的行为或属性。
Leaf叶子构件:叶子对象,其下再也没有其他的分支,也就是遍历的最小单位。
从实现思路看,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方法拿到到所有的计算机类书名,其它的代码基本和小说统计中的是一样的。
从实现思路看,现在你才完成了两类书籍的统计功能,后面还有医学类、自然类、历史类、法律类、z治类、哲学类、旅游类、美食类等等等等书籍。你突然意识到了一些问题的严重性,工作量大倒还不算什么,但再这么写下去,你的方法就要爆炸了,这么多的方法让人看都看不过来,别提怎么采用了。
在这个场景下,这个时候你只好向你的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可是大忙人,早就一溜烟跑开了。
总结
组合模式的优点:
理解这一步时,能够灵活的组合局部对象和整体对象之间的关心,对客户端来说,局部对象和整体对象的调用没有差别,使调用轻松。
组合模式的缺点:
1.组合操作的成本很高,如果一个对象树中有很多子对象,可能一个轻松的调用就可能使系统崩溃;
2.对象持久化的问题,组合模式是树形结构,不能很好地在关系数据库中保存数据,但是却很适合用来xml持久化。
组合模式的适用场景:
1.维护和展示部分—整体关系得场景,如树形菜单、文件和文件夹管理。
2.从一个整体中能够独立出部分模块或功能的场景。
您可能感兴趣的文章:
- 设计模式中的观察者模式在Ruby编程中的运用实例解析
- 实例解析Ruby设计模式开发中对观察者模式的实现
- 深入剖析Ruby设计模式编程中对命令模式的相关采用
- Ruby设计模式编程中对外观模式的应用实例分析
- 设计模式中的模板方法模式在Ruby中的应用实例两则
- 实例解析Ruby设计模式编程中Strategy策略模式的采用
- 实例讲解Ruby采用设计模式中的装饰器模式的方法
- Ruby设计模式编程中采用Builder建造者模式的实例
- 详解Ruby设计模式编程中对单例模式的运用
- Ruby设计模式编程之适配器模式实战攻略
- Ruby采用设计模式中的代理模式与装饰模式的代码实例
- Ruby中采用设计模式中的轻松工厂模式和工厂方法模式
- 解析proxy代理模式在Ruby设计模式开发中的运用
-
09.03
如何选择ai写作软件哪个好,WPS AI助力文档创作效率与质量
-
09.03
如何利用AI写作机器人提升文档创作效率,成为办公自动化的利器
-
09.03
晶圆代工“双雄”同日发布业绩,港股走势不一
-
09.03
轻松打开AI格式文件,四种简便做法助你快速解决问题
-
09.03
Futuristic Mall Fashion Scene
-
09.03
掌握Excel清除公式的实用技巧,提升数据管理效率
-
- 逻辑游戏有哪些好玩的逻辑游戏推荐
- 09.03
-
-
- MiniMax_Agent工具调用频率受限怎么办
- 09.03
-
-
-
-
下载
- |
-
-
下载
- 《行尸走肉第一章》免安装中文汉化硬盘版下载
- 单机|436 MB
- 一款以动作冒险为主题的游戏
-
-
下载
- 《街头霸王X铁拳》免安装中文汉化硬盘版下载
- 单机|111MB
- 一款非常好玩的格斗游戏
-
-
下载
- |
-
-
下载
- 《暗黑破坏神3》免安装繁体中文正式版下载
- 单机|7630 MB
- 一款以角色扮演为主题的游戏
-
-
下载
- 《马克思佩恩3》免安装硬盘版下载
- 单机|27033 MB
- 一款以第三人称射击为主题的游戏