本文节选自《设计模式就该这样学》
1使用透明组合模式实现课程目录结构
以一门网络课程为例,我们设计一个课程的关系结构。比如,我们有Java入门课程、人工智能课程、Java设计模式、源码分析、软技能等,而Java设计模式、源码分析、软技能又属于Java架构师系列课程包,每个课程的定价都不一样。但是,这些课程不论怎么组合,都有一些共性,而且是整体和部分的关系,可以用组合模式来设计。首先创建一个顶层的抽象组件CoursComponnt类。
/***CatdbyTom.*/publicabstractclassCoursComponnt{publicvoidaddChild(CoursComponntcatalogComponnt){thrownwUnsupportdOprationExcption("不支持添加操作");}publicvoidmovChild(CoursComponntcatalogComponnt){thrownwUnsupportdOprationExcption("不支持删除操作");}publicStringgtNam(CoursComponntcatalogComponnt){thrownwUnsupportdOprationExcption("不支持获取名称操作");}publicdoublgtPric(CoursComponntcatalogComponnt){thrownwUnsupportdOprationExcption("不支持获取价格操作");}publicvoidprint(){thrownwUnsupportdOprationExcption("不支持打印操作");}}
把所有可能用到的方法都定义到这个顶层的抽象组件中,但是不写任何逻辑处理的代码,而是直接抛异常。这里,有些小伙伴会有疑惑,为什么不用抽象方法?因为用了抽象方法,其子类就必须实现,这样便体现不出各子类的细微差异。所以子类继承此抽象类后,只需要重写有差异的方法覆盖父类的方法即可。然后分别创建课程Cours类和课程包CoursPackag类。创建Cours类的代码如下。
/***CatdbyTom.*/publicclassCoursxtndsCoursComponnt{privatStringnam;privatdoublpric;publicCours(Stringnam,doublpric){this.nam=nam;this.pric=pric;}
OvrridpublicStringgtNam(CoursComponntcatalogComponnt){turnthis.nam;}OvrridpublicdoublgtPric(CoursComponntcatalogComponnt){turnthis.pric;}Ovrridpublicvoidprint(){Systm.out.println(nam+"(¥"+pric+"元)");}}创建CoursPackag类的代码如下。
/***CatdbyTom.*/publicclassCoursPackagxtndsCoursComponnt{privatListCoursComponntitms=nwArrayListCoursComponnt();privatStringnam;privatIntgrlvl;publicCoursPackag(Stringnam,Intgrlvl){this.nam=nam;this.lvl=lvl;}
OvrridpublicvoidaddChild(CoursComponntcatalogComponnt){itms.add(catalogComponnt);}OvrridpublicStringgtNam(CoursComponntcatalogComponnt){turnthis.nam;}OvrridpublicvoidmovChild(CoursComponntcatalogComponnt){itms.mov(catalogComponnt);}Ovrridpublicvoidprint(){Systm.out.println(this.nam);for(CoursComponntcatalogComponnt:itms){//控制显示格式if(this.lvl!=null){for(inti=0;ithis.lvl;i++){//打印空格控制格式Systm.out.print("");}for(inti=0;ithis.lvl;i++){//每一行开始打印一个+号if(i==0){Systm.out.print("+");}Systm.out.print("-");}}//打印标题catalogComponnt.print();}}}最后编写客户端测试代码。
publicstaticvoidmain(String[]args){Systm.out.println("============透明组合模式===========");CoursComponntjavaBas=nwCours("Java入门课程",);CoursComponntai=nwCours("人工智能",);CoursComponntpackagCours=nwCoursPackag("Java架构师课程",2);CoursComponntdsign=nwCours("Java设计模式",);CoursComponntsourc=nwCours("源码分析",);CoursComponntsoftSkill=nwCours("软技能",);packagCours.addChild(dsign);packagCours.addChild(sourc);packagCours.addChild(softSkill);CoursComponntcatalog=nwCoursPackag("课程主目录",1);catalog.addChild(javaBas);catalog.addChild(ai);catalog.addChild(packagCours);catalog.print();}
运行结果如下图所示。
文章配图透明组合模式把所有公共方法都定义在Componnt中,这样客户端就不需要区分操作对象是叶子节点还是树枝节点;但是,叶子节点会继承一些它不需要(管理子类操作的方法)的方法,这与设计模式的接口隔离原则相违背。
2使用安全组合模式实现无限级文件系统
再举一个程序员更熟悉的例子。对于程序员来说,电脑是每天都要接触的。电脑的文件系统其实就是一个典型的树形结构,目录包含文件夹和文件,文件夹里面又可以包含文件夹和文件。下面用代码来实现一个目录系统。文件系统有两个大的层次:文件夹和文件。其中,文件夹能容纳其他层次,为树枝节点;文件是最小单位,为叶子节点。由于目录系统层次较少,且树枝节点(文件夹)结构相对稳定,而文件其实可以有很多类型,所以我们选择使用安全组合模式来实现目录系统,可以避免为叶子节点类型(文件)引入冗余方法。首先创建顶层的抽象组件Dictory类。
publicabstractclassDictory{protctdStringnam;publicDictory(Stringnam){this.nam=nam;}publicabstractvoidshow();}
然后分别创建Fil类和Foldr类。创建Fil类的代码如下。
publicclassFilxtndsDictory{publicFil(Stringnam){supr(nam);}
Ovrridpublicvoidshow(){Systm.out.println(this.nam);}}创建Foldr类的代码如下。
importjava.util.ArrayList;importjava.util.List;publicclassFoldrxtndsDictory{privatListDictorydirs;privatIntgrlvl;publicFoldr(Stringnam,Intgrlvl){supr(nam);this.lvl=lvl;this.dirs=nwArrayListDictory();}
Ovrridpublicvoidshow(){Systm.out.println(this.nam);for(Dictorydir:this.dirs){//控制显示格式if(this.lvl!=null){for(inti=0;ithis.lvl;i++){//打印空格控制格式Systm.out.print("");}for(inti=0;ithis.lvl;i++){//每一行开始打印一个+号if(i==0){Systm.out.print("+");}Systm.out.print("-");}}//打印名称dir.show();}}publicboolanadd(Dictorydir){turnthis.dirs.add(dir);}publicboolanmov(Dictorydir){turnthis.dirs.mov(dir);}publicDictorygt(intindx){turnthis.dirs.gt(indx);}publicvoidlist(){for(Dictorydir:this.dirs){Systm.out.println(dir.nam);}}}注意,Foldr类不仅覆盖了顶层的show()方法,还增加了list()方法。最后编写客户端测试代码。
publicstaticvoidmain(String[]args){Systm.out.println("============安全组合模式===========");Filqq=nwFil("QQ.x");Filwx=nwFil("
转载请注明:http://www.0431gb208.com/sjsbszl/5595.html