组合模式,就是在一个对象中包含其他对象,这些被包含的对象可能是终点对象(不再包含别的对象),也有可能是非终点对象(其内部还包含其他对象,或叫组对象),我们将对象称为节点,即一个根节点包含许多子节点,这些子节点有的不再包含子节点,而有的仍然包含子节点,以此类推。很明显,这是树形结构,终结点叫叶子节点,非终节点(组节点)叫树枝节点,第一个节点叫根节点。同时也类似于文件目录的结构形式:文件可称之为终节点,目录可称之为非终节点(组节点)。
在我写外观模式的时候,我是举最近在做的一个考勤的例子,不熟悉的小伙伴可以去看一下前面的文章哦,在那个例子中我们分析了一下,考勤中每种类别员工的工作日计算方式是不一样的,比如说一般员工周一到周五上班,有些员工的工作比较累上一天休一天,那么他们每个月上班天数是不一样的;但是出勤的计算天数是一样的,根据打卡来计算。当时我的处理方式是,把计算打卡天数的方法写成抽象类的默认方法供特殊员工去重写,出勤天数写成抽象方法,每一个继承它的类都各自去实现它。但是实际中我们可能还会遇到更多的情况:比如说Boss打卡,但是不需要计算出勤天数;部门领导考勤信息要含有下级员工的考勤信息。
不知道上面描述的是否清晰,换句话说:我们把员工抽象成一个类,虽然不同类别员工的的操作不同,但是我们可以在实现类的方法实现中具体定义。大家可以看一下我前面写的外观模式了解一下。下面我们一步一步的来看
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。 这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
当时写考勤的代码的时候,我并没有学过组合模式,只是觉得把两个类相似部分抽离出来,特有部分各自去实现就好,但是今天我发现那就是用了一点组合模式的东西。这也说明了我们可以在项目中运用多种模式。
那我们继续看考勤的例子,首先我们要抽象出来考勤这个类。这里面getWorkDay是获取工作日的方法,一般员工是每个月的周一到周五(节假日和调休这里不考虑),特殊员工是上一天休息一天。所以这个方法抽象一下,让他们去自己实现自己的方法。getRealWorkDay()这个方法是获取实际的出勤天数。两类员工的出勤天数计算都是一样的,传入ID,在数据库查找打卡天数就可以了。所以这里我们直接实现这个方法。
abstract class AbstractAttence {
public abstract void getWorkDay();
public void getRealWorkDay(int userID) {
System.out.println(userID + "的人员出勤天数为XX天");
}
}
那么一般员工就要这样来写了:
//一般工作人员打卡
class Card extends AbstractAttence {
@Override
public void getWorkDay() {
System.out.println("一般员工,周一到周五打卡,工作日大约22天");
}
}
而特殊员工
//特殊人员打卡
class CardSpecial extends AbstractAttence {
@Override
public void getWorkDay() {
System.out.println("特殊员工:柜员,工作日大约为15天");
}
}
此外你也可以换一种方式去解读组合模式,我的例子中是两种员工都拥有这个两个方法,只不过是其中一个方法每种员工的实现方式是不一样的,但是有些员工区别于这两种,他们工作日跟第一种员工相同,周一到周五上班,但是他们不用计算出勤天数,换句话说,他们出勤率是100%,比如老板。。。这个时候我们就要这样写了:
//老板打卡
class Boss extends AbstractAttence {
@Override
public void getWorkDay() {
System.out.println("我是Boss,我周一到周五打卡");
}
@Override
public void getRealWorkDay(int userID) {
System.out.println("我是Boss,我不用计算出勤天数");
}
}
这样说完了,我们再看看对于一组的概念,就是对于一组相似的对象,我们依据树形结构来组合对象,然后用来表示部分以及整体层次。上面例子中我忽略了树形结构,因为我觉得没有必要,它跟节点类似,每一个节点下面有一个相似的类作为叶子节点。就像下面一样,某一类员工的考勤中会包含下属的考勤信息,这个时候,这一类高级员工的实体类中,包含了自己下属的考勤信息的增加方法
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、节点自由增加。
缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
使用场景:部分、整体场景,如树形菜单,文件、文件夹的管理。
注意事项:定义时为具体类。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有