接上篇,本文介绍结构型模式里的组合模式、装饰模式、外观模式。

一、组合模式(Composite)

组合模式:将对象组合成树形结构,表示“部分--整体”的层次结构。最终达到单个对象和组合对象的使用具有一致性。单看这句话貌似有点抽象,其实比较简单。

以李云龙的独立团为例,目的要统计赵嘉宇一战共歼灭敌人多少个。最高的级别是团,一个团有若干个营,一个营有若干个排,一个排有若干个战士。(为了简化问题,排下面就不设行政单位了)。很自然的,李云龙给营长开会回去给老子统计。营长回去给各个排长开会,赶紧统计。排长回去问问大家,数字报上去,汇报结束。这就是典型的组合模式。

组合模式涉及到Component(部件)、Leaf(叶子)、Composite(组合对象)三个概念。其中Component是组合中的对象声明接口,实现所有类共有接口的缺省行为。本例中Component类的设计至少有三个方法:addMember()(对应某个排新来一个战士)、deleteMember(某个士兵战死了,排长要将其删除)、getKillNumber()(这是通用行为获得杀敌数)。Leaf表示爷子接点,这里的士兵就是最底层的Leaf,他没有添加member的权利。1排排长、2排排长都是leaf,他们可以添加member。每个类里应维护一个List,用于管理属于它的member。那么这个排长就属于

一种组合了。下面附个完整例子:
1、Component 
public abstract class Employer {
    private String name;
    public void setName(String name) {
        this.name = *ame;
    }
    public String getName() {
        return this.name;
    }
    public abstract void add(Employer employer*;
    public abstract void delete(Employer employer);
    public List employers;
    public void printInfo*) {
        System.out.println(name);
    }
    public List getE*ployers() {
        return this.employers;
    }
}
注意:这里为什么使用absract,而不使用interface,参见上篇。
2.Leaf 这里定义的程序员和项目经理是平级的,都是给下面的
项目经理打工的,没有子节点。
public class Programmer extends Employer {
    public Programmer(String name) {
        setName(name);
        employers = null;//程序员, 表示没有下属了
    }
    public void add(Employer employer) {
        
    }
    public void delete(Employer employer) {
        
    }
}

public class ProjectAssistant extends Employer {
    public ProjectAssistant(String name) {
        setName(name);
        employers = *ull;//项目助理, 表示没有下属了
    }
    public void add(Employer employer) {
        
    }
    public void delete(Employer employer) {
        
    }
}
3.Composite 组合
public class ProjectManager extends E*ployer {
    public ProjectManager(String name) {
        setName(name);
        employers = new A*rayList();
    }
    public void add(Employer employer) {
        employers.add(employer);
    }
    public void delete(Emplo*er employer) {
        employers.remove(employer);
    }
}
测试代码:
public class Test {
    public static void main(String[] args) {
        Employer pm = new ProjectManager("项目经理");
        Emplo*er pa = new ProjectAssistant("项目助理");
        Employer progra*mer1 = new Programmer("程序员一");
        Employer programmer2 = new Programmer("程序员二");
        
        pm.add(pa);//为项目经理添加项目助理
        pm.add(programmer2);//*项目经理*加程序员
        
        List ems = pm.getEm*loyers();
        for (Employer em : ems) {
            System.out.println(em.getNam*());
        }
   }
}
适用性:    
1.你想表示对象的部分-整体层次结构。
2.你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
注:组合模式可以很好的扩展,像开头说的统计歼敌数量的例子,排长和营长都是组合,但他们又是上一级的叶子,同时自己也有叶子。
另,http://blog.csdn.net/jason0539/article/details/22642281
http://blog.csdn.net/guolin_blog/article/details/9153753 可以参考辅助理解。

二、装饰模式Decorator

动态给一个对象添加额外的职责,在增加功能方面,Decorator模式比生成子类更加灵活。
参与者:
1.Component 定义一个对象接口,可以给这些对象动态添加职责。
public interface Person {
    void eat();
}
2.ConcreteComponent定义一个对象,可以给这个对象添加一些职责。
public class Man implements Person {
public void eat() {
System.out.println("男人在吃");
}
}
3.Decorator 维持一个指向Component对象的指针,并定义一个与Component接口一致的接口。
public abstract class Decorator implements Person {
    protected Person person;
    public void setPerson(Person person) {
        this.person = person;
    }
    public void eat() {
        person.eat();
    }
}
4.ConcreteDecorator向组件添加职责
public class ManDecoratorA extends Decorator {

public void eat() {
        super.eat();
        reEat();
        System.out.println("ManDecoratorA类");
    }
    public void reEat() {
        System.out.println("再吃一顿饭");
    }
}

public class ManDecoratorB extends Decorator {
    public void eat() {
        super.eat();
        Syst*m.out.println("===============");
        System.out.println("ManDecoratorB类");
    }
}
测试代码:
public class Test {
    public static void main(Strin*[] args) {
        Man man = new Man();
        ManDecoratorA md1 = new ManDecoratorA();
        ManDecoratorB md2 = new ManDecoratorB();
        
        md1.setPerson(man);
        md2.setPerson(md1);
        md2.eat();
    }
}
适用性:
1.在不影响其他*象的情况下,以动态、透明的方式给单个对象添加职责。
2.处理那些可以撤消的职责。
3.当不能采用生成子类的方法进行扩充时。

可以看到装饰模式可以在不创造更多的子类模式下,将对象的功能加以扩展。装饰模式和类继承的区别:
1)装饰模式是一种动态行为,对已经存在类进行随意组合,而类的继承是一种静态的行为,一个类定义成什么样的,该类的对象便具有什么样的功能,无法动态的改变。
2)装饰模式扩展的是对象的功能,不需要增加类的数量,而类继承扩展是类的功能,在继承的关系中,如果我们想增加一个对象的功能,我们只能通过继承关系,在子类中增加两个方法。
装饰与继承比较:
1装饰模式是在不改变原类文件和使用继承的情况下,动态的扩展一个对象的功能,它是通过创建一个包装对象,也就是装饰来包裹真是的对象。
2装饰模式把对客户端的调用委派给被装饰的类,装饰模式的关键在于这种扩展完全透明的。
注:有人会说这里的ManDecoratorB、ManDecoratorA还是定义了新的子类的,这是为了示例在不同的层次上定义的,如果增加一个层次的功能的话只需定义一个ManDecoratorA里的reEat()里写上就行了。可以看到最大的不同是在对原来的调用不影响,用户不知不觉调用原来的eat()其实已经多吃了两碗,哈哈。这是类的继承无法达到的。也可再看看此例:http://www.cnblogs.com/hnrainll/archive/2012/03/23/2414180.html

三、外观模式Facade

为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这些子系统更加容易使用。比如对于李云龙来说,要完成一次战役指挥,他只需发布命令:准备战斗、开火、打扫战场回家。这三个步骤,而每个步骤,具体到每个营、每个排都要做大量的准备和布置。但这些不是老李关心的。简而言之,就是把子类的一系列行为按类别封装起来,对外只提供一个统一的接口,这就是外观模式。
1、一系列的子类
public class ServiceAImpl implements ServiceA {
    public void methodA() {
        System.out.println("这是服务A");
    }
}
public class ServiceBImpl implements ServiceB {
    public void methodB() {
        System.out.println("这是服务B");
    }
}
public class ServiceCImpl implements ServiceC {
    public void methodC() {
        System.out.println("这是服*C");
    }
}
2.Facade
public class Facade {

ServiceA s*;
    
    ServiceB sb;
    
    ServiceC sc;
    
    public Facade() {
        sa = new S*rviceAImpl();
        sb = new *erviceBImpl();
        sc = new ServiceCImpl(); 
    }
    
    public void methodA() {
        sa.methodA();
        sb.methodB();
    }
    
    publi* void methodB() {
        s*.methodB();
        sc.methodC();
    }
    
    public void methodC() {
        sc.methodC();
        sa.methodA();
    }
}
注:就是把三个子类的方法重新封装了下,统一对外提供接口。但这个例子本身举得不太好。
测试代码:
public class Test {
    public static void main(String[] args) {
    ServiceA sa = new ServiceAImpl();
    ServiceB sb = new ServiceBImpl();
        
        sa.methodA();
        sb.methodB();
        
        System.out.println("========");
        //facade
        Facade facade = new Facade();
        facade.methodA();
        facade.methodB();
    }
}
所以外观模式是很简单的一种,也可参见链接。

Java经典23种设计模式之结构型模式(二)相关推荐

  1. 备战面试日记(3.3) - (设计模式.23种设计模式之结构型模式)

    本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试. 记录日期:2022.1.9 大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习. 文章 ...

  2. Java经典23种设计模式之行为型模式(三)

    本文接着介绍11种行为型模式里的备忘录模式.观察者模式.状态模式. 一.备忘录模式 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可以将该对象恢复到原先保存的状 ...

  3. JAVA23种设计模式(2)-结构型模式7种

    JAVA23种设计模式(2)-结构型模式7种 把类结合在一起形成更大的结构 适配器模式(adapter) 一句话:将一个类的接口转换成另一种接口.让原本接口不兼容的类可以兼容 这是平时比较常见的一种模 ...

  4. Java中的23个设计模式 【结构型模式】 中的 【享元模式】

    文章目录 设计模式分类 享元模式(FlyWeight) 介绍 案例--围棋软件设计 享元模式实现 开发中的应用场景 优缺点 优点 缺点 代码 抽象享元类 具体享元类,设置内部状态 非共享享元类,设置外 ...

  5. Java23种设计模式——11.结构型模式之享元模式

    Java中除去有设计原则之外,还有23中设计模式. 这些模式都是前辈们一点一点积累下来,一直在改进,一直在优化的,而这些设计模式可以解决一些特定的问题. 并且在这些模式中,可以说是将语言的使用体现的淋 ...

  6. Java最全的设计模式之结构型模式

    这篇接着上篇,结构型模式包含了七种,没有看过上篇的可以点击超链接 Java设计模式之创建型模式 Java设计模式之创建型模式 9.适配器模式 9.1结构型模式 9.2适配器模式的定义 9.3适配器模式 ...

  7. 备战面试日记(3.4) - (设计模式.23种设计模式之行为型模式)

    本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试. 记录日期:2022.1.12 大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习. 文 ...

  8. 备战面试日记(3.2) - (设计模式.23种设计模式之创建型模式)

    本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试. 记录日期:2022.1.6 大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习. 文章 ...

  9. 经典:从追MM谈Java的23种设计模式

    2019独角兽企业重金招聘Python工程师标准>>> 从追MM谈Java的23种设计模式1.FACTORY-追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然 ...

最新文章

  1. 安装最新Spree出现error:spree_core requires will_paginate (= 3.0.pre2, runtime)
  2. 短信验证码“最佳实践”
  3. leancloud的技术面试指南
  4. PHP的的指针的特性
  5. Python 中的新式类和经典类的区别?
  6. restful api和普通api有什么特点_Django REST Framework教程(1): 什么是序列化和RESTful的API
  7. iis 在站点中新建虚拟目录站点之后,虚拟目录中的 web.config 与 主站点中的 web.config冲突解决方案...
  8. 使用Pycharm运行TensorFlow,Virtualenv安装TensorFlow
  9. mysql5.5.50安装包_影视混剪每天收入400多??总结了50多款软件
  10. 有趣 的java代码_[分享]几段有趣的JAVA代码
  11. FileUpload类中FileUpload1.FileName和FileUpload1.PostedFile.FileName的区别
  12. SVG黑科技微信排版『Apple连续向上滑动』模板代码
  13. React控制台警告Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until
  14. 神奇的伊娃(eval),魔鬼的伊娃(eval)
  15. matlab进行fm调制与解调,基于matlab的fm信号调制与解调.doc
  16. 【知识图谱】 一个有效的知识图谱是如何构建的?
  17. Android 即时音效SoundPool
  18. 拼多多按关键词搜索示例
  19. Windows 源码学习,WRK 和 ReactOS
  20. Windows 10字体模糊发虚! 如何解决?

热门文章

  1. JS中innerText和innerHTML的区别
  2. bwa是linux系统下软件,bwa 软件用法简介
  3. python笔记-dumps()与loads()的使用
  4. 手把手带你使用Vue实现一个图片水平瀑布流插件
  5. html、aps网页设计,Dreamweaver8通过IIS建立站点对网页进行预览,设置详细方法
  6. String数组排序去重
  7. Linux docker(01) 基础操作
  8. 使用iconv编程进行字符集转换
  9. 看完这篇你还敢说分不清 Java 类 对象 实例 变量间的区别?
  10. IT里的精英美女!(转)