前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java设计模式(十)组合模式

Java设计模式(十)组合模式

作者头像
每天学Java
发布2020-06-01 18:04:49
7820
发布2020-06-01 18:04:49
举报
文章被收录于专栏:每天学Java

组合模式,就是在一个对象中包含其他对象,这些被包含的对象可能是终点对象(不再包含别的对象),也有可能是非终点对象(其内部还包含其他对象,或叫组对象),我们将对象称为节点,即一个根节点包含许多子节点,这些子节点有的不再包含子节点,而有的仍然包含子节点,以此类推。很明显,这是树形结构,终结点叫叶子节点,非终节点(组节点)叫树枝节点,第一个节点叫根节点。同时也类似于文件目录的结构形式:文件可称之为终节点,目录可称之为非终节点(组节点)。

在我写外观模式的时候,我是举最近在做的一个考勤的例子,不熟悉的小伙伴可以去看一下前面的文章哦,在那个例子中我们分析了一下,考勤中每种类别员工的工作日计算方式是不一样的,比如说一般员工周一到周五上班,有些员工的工作比较累上一天休一天,那么他们每个月上班天数是不一样的;但是出勤的计算天数是一样的,根据打卡来计算。当时我的处理方式是,把计算打卡天数的方法写成抽象类的默认方法供特殊员工去重写,出勤天数写成抽象方法,每一个继承它的类都各自去实现它。但是实际中我们可能还会遇到更多的情况:比如说Boss打卡,但是不需要计算出勤天数;部门领导考勤信息要含有下级员工的考勤信息。

不知道上面描述的是否清晰,换句话说:我们把员工抽象成一个类,虽然不同类别员工的的操作不同,但是我们可以在实现类的方法实现中具体定义。大家可以看一下我前面写的外观模式了解一下。下面我们一步一步的来看

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。 这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。

当时写考勤的代码的时候,我并没有学过组合模式,只是觉得把两个类相似部分抽离出来,特有部分各自去实现就好,但是今天我发现那就是用了一点组合模式的东西。这也说明了我们可以在项目中运用多种模式。

那我们继续看考勤的例子,首先我们要抽象出来考勤这个类。这里面getWorkDay是获取工作日的方法,一般员工是每个月的周一到周五(节假日和调休这里不考虑),特殊员工是上一天休息一天。所以这个方法抽象一下,让他们去自己实现自己的方法。getRealWorkDay()这个方法是获取实际的出勤天数。两类员工的出勤天数计算都是一样的,传入ID,在数据库查找打卡天数就可以了。所以这里我们直接实现这个方法。

代码语言:javascript
复制
abstract class AbstractAttence  {


    public abstract void getWorkDay();


    public void getRealWorkDay(int userID) {
        System.out.println(userID + "的人员出勤天数为XX天");
    }
}

那么一般员工就要这样来写了:

代码语言:javascript
复制
//一般工作人员打卡
class Card extends AbstractAttence {

    @Override
    public void getWorkDay() {
        System.out.println("一般员工,周一到周五打卡,工作日大约22天");
    }


}

而特殊员工

代码语言:javascript
复制
//特殊人员打卡
class CardSpecial extends AbstractAttence {

    @Override
    public void getWorkDay() {
        System.out.println("特殊员工:柜员,工作日大约为15天");
    }


}

此外你也可以换一种方式去解读组合模式,我的例子中是两种员工都拥有这个两个方法,只不过是其中一个方法每种员工的实现方式是不一样的,但是有些员工区别于这两种,他们工作日跟第一种员工相同,周一到周五上班,但是他们不用计算出勤天数,换句话说,他们出勤率是100%,比如老板。。。这个时候我们就要这样写了:

代码语言:javascript
复制
//老板打卡
class Boss extends AbstractAttence {

    @Override
    public void getWorkDay() {
        System.out.println("我是Boss,我周一到周五打卡");
    }

    @Override
    public void getRealWorkDay(int userID) {
        System.out.println("我是Boss,我不用计算出勤天数");
    }
}

这样说完了,我们再看看对于一组的概念,就是对于一组相似的对象,我们依据树形结构来组合对象,然后用来表示部分以及整体层次。上面例子中我忽略了树形结构,因为我觉得没有必要,它跟节点类似,每一个节点下面有一个相似的类作为叶子节点。就像下面一样,某一类员工的考勤中会包含下属的考勤信息,这个时候,这一类高级员工的实体类中,包含了自己下属的考勤信息的增加方法

代码语言:javascript
复制
abstract class AbstractAttence  {
    List<AbstractAttence> list = new ArrayList<>();
    public void addAttemce(AbstractAttence abstractAttence){
     list.add(abstractAttence);
    }

    public abstract void getWorkDay();


    public void getRealWorkDay(int userID) {
        System.out.println(userID + "的人员出勤天数为XX天");
    }
}

意图:将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

何时使用: 1、您想表示对象的部分-整体层次结构(树形结构)。 2、您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

如何解决:树枝和叶子实现统一接口,树枝内部组合该接口。

关键代码:树枝内部组合该接口,并且含有内部属性 List,里面放 Component。

应用实例: 1、算术表达式包括操作数、操作符和另一个操作数,其中,另一个操作符也可以是操作数、操作符和另一个操作数。 2、在 JAVA AWT 和 SWING 中,对于 Button 和 Checkbox 是树叶,Container 是树枝。

优点: 1、高层模块调用简单。 2、节点自由增加。

缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

使用场景:部分、整体场景,如树形菜单,文件、文件夹的管理。

注意事项:定义时为具体类。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 每天学Java 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档