以下是某公司的办公系统的结构,如果要去开发这样一个系统,在编写代码之前要好好整理一下思维,否则,如果单纯的去实现的话可能会变得繁琐而麻烦。
某公司的办公管理系统
如果细看,会发现每个分公司、每个办事处都与总部有着相同的组织架构,就是人力资源部与财务部。如果分开去处理这样的部门,要不断的去包装各个机构的人力资源部与财务部,这样的叠加所造成的工作量是极大的,而且如果想要更改一些部门的策略,会变得异常麻烦。最重要的一点是总部的人力资源部与财务部与各个办事处的部门所用的系统有着相同的功能。这样的关系有着自相似的特点,很容易就能联想到了一种特殊的函数的特性,那就是---递归。递归是满足自相似的一种表现形式,有着层层深入的特点。如果按照这样的特点来考虑的话,或许会发现点什么新鲜的东西。
根据以上的分析,不自觉的想到了这样的一种类的设计形式,去满足以上的特性:
设计一个基类接口,其中这个基类的接口包含所有部门的功能,然后创建两个类去继承自它,它们分别是人力资源部与财务部,这样人力资源部与财务部们就能在各自的实体类中实现各自的功能了。然而此时还需要一个单独的类去管理他们(封装他们),这样就形成了一个单独的组织单元,但是由于单元之间能够相互连接形成层级关系,所以,单元中需要添加一个集合去链接各个单元。由于这个集合承载着链接的功能,所以这个集合需要放在基类中。使用的时候,通过实例根节点基类,然后去装配各个部门的组织单元,使用集合去链接各个单元,最后将链接之后的结果装配到根节点基类也就完成了整个脉络的系统。
这样的设计其实就是今天要记录的组合模式,组合模式的结构图如下所示:
组合模式其实叶子节点就是上述公司的财务部门
与人力资源部
,而枝节点点就是包含着他们的各个分部
,分部
负责叶子结点的操作与一些基本的业务逻辑
。最后通过装配实例到最上级别的根节点Component
。客户端只需要去实例Component
既可完成整个系统的创建。
为了说明这个模式的特点,这里我们就以开始的实例来说明。
根据分析我们知道,财务部
与人力资源部
不断的被各个分部门所使用,而各个分部门的职责能够创建
与移除
他们,所以对应与业务的操作类而言有着add()
与remove()
等方法的操作。为了保证各个分部门
与各个分部门主管
的连接关系,这里我们需要在业务控制类
中去创建一个集合去处理这些业务逻辑
,保证组合形式的关联。
首先我们先创建一个接口(ComponmentRoot.swift)
。如下:
//
// ComponmentRoot.swift
// CompositeModelDemo
//
// Created by lcc on 2017/3/9.
// Copyright © 2017年 early bird international. All rights reserved.
//
import Cocoa
protocol ComponmentDelegate {
var name:String?{get set};
//添加子部门
func add(componment:ComponmentDelegate);
//移除子部门
func remove(componment:ComponmentDelegate);
//展示当前的部门职责以及当前的层级深度
func display(currentDepth:Int);
}
然后创建对应的部门类,人力资源部(ResourcePerson)
与财务部(FinanceDepartment)
,它们分别实现ComponmentRoot
接口。如下:
//
// ResourcePerson.swift
// CompositeModelDemo
//
// Created by lcc on 2017/3/9.
// Copyright © 2017年 early bird international. All rights reserved.
//
import Cocoa
class ResourcePerson:ComponmentDelegate {
var name: String?;
init(name:String) {
self.name = name;
}
func add(componment: ComponmentDelegate) {
print("不能够增加子节点,我是叶子,没有权限-" + self.name!);
}
func remove(componment: ComponmentDelegate) {
print("不能删除节点,我是叶子,没有权限-" + self.name!);
}
func display(currentDepth: Int) {
print("\(String.init(repeating: "-", count: currentDepth))" + self.name!);
}
}
//
// FinanceDepartment.swift
// CompositeModelDemo
//
// Created by lcc on 2017/3/9.
// Copyright © 2017年 early bird international. All rights reserved.
//
import Cocoa
class FinanceDepartment:ComponmentDelegate {
var name: String?;
init(name:String) {
self.name = name;
}
func add(componment: ComponmentDelegate) {
print("不能够增加子节点,我是叶子,没有权限-" + self.name!);
}
func remove(componment: ComponmentDelegate) {
print("不能删除节点,我是叶子,没有权限-" + self.name!);
}
func display(currentDepth: Int) {
print("\(String.init(repeating: "-", count: currentDepth))" + self.name!);
}
}
由于各个部门之间有着一个上属组织
,这个上属组织
起着各个分部的连接功能(业务逻辑链接操作)
,所以在部门组织(PartDealDepartment)
中承载着添加
与删除
它所链接的子部门
,为了能够对其子部门
进行对应的操作,所以在这样的类中同样实现了接口ComponmentRoot
的方法,还有一点就是要存储它的子部门,从而起到链接子部门的关系。所以PartDealDepartment
除了实现ComponmentRoot
接口外,还需要添加一个集合去保存对应的子部门,也就是叶子结点。
//
// PartDealDepartment.swift
// CompositeModelDemo
//
// Created by lcc on 2017/3/9.
// Copyright © 2017年 early bird international. All rights reserved.
//
import Cocoa
class PartDealDepartment:ComponmentDelegate{
var name: String?;
init(name:String) {
self.name = name;
}
var childArray: NSMutableArray?;
func add(componment: ComponmentDelegate) {
if childArray == nil {
childArray = NSMutableArray.init();
}
self.childArray?.add(componment);
}
func remove(componment: ComponmentDelegate) {
self.childArray?.remove(componment);
}
func display(currentDepth: Int) {
//显示当前的层级
print("\(String.init(repeating: "-", count: currentDepth))" + self.name!);
if childArray != nil {
for var componment in childArray!{
//显示所属之下的部门
(componment as! ComponmentDelegate).display(currentDepth: currentDepth + 1);
}
}
}
}
在使用的时候,我们只需要对各个部门进行链接即可,这也体现了组合模式
的优点:对单个对象和组合对象的使用有着一致性
。
//
// main.swift
// CompositeModelDemo
//
// Created by lcc on 2017/3/9.
// Copyright © 2017年 early bird international. All rights reserved.
//
import Foundation
var root:ComponmentDelegate = PartDealDepartment.init(name: "北京公司总部");
root.add(componment: ResourcePerson.init(name: "人力资源部(北京)"));
root.add(componment: FinanceDepartment.init(name: "财务部(北京)"));
var comp:PartDealDepartment = PartDealDepartment.init(name: "上海华东分公司");
comp.add(componment: ResourcePerson.init(name: "人力资源部(上海分公司)"));
comp.add(componment: FinanceDepartment.init(name: "财务部(上海分公司)"));
var comp2:PartDealDepartment = PartDealDepartment.init(name: "南京办事处");
comp2.add(componment: ResourcePerson.init(name: "人力资源部(南京办事处)"));
comp2.add(componment: FinanceDepartment.init(name: "财务部(南京办事处)"));
var comp3:PartDealDepartment = PartDealDepartment.init(name: "杭州办事处");
comp3.add(componment: ResourcePerson.init(name: "人力资源部(杭州办事处)"));
comp3.add(componment: FinanceDepartment.init(name: "财务部(杭州办事处)"));
//添加链接组合
comp.add(componment: comp2);
comp.add(componment: comp3);
root.add(componment: comp);
//显示组合之后的链接关系
root.display(currentDepth: 1);
结果如下所示:
组合模式最后,说一下这种模式的定义与使用场景。
官方定义:
将对象组合成树行结构以表示『部分』-『整理』的层次结构,组合模式使得用户对单个对象与组合对象的使用具有一致性。
使用场景:
当你发现需求中体现了部分与中体的层次的结构的时候,并且组合对象与单个对象职能相似,统一的使用组合中所有的对象时,可以考虑去使用组合模式来进行设计了。
参考:
《大话设计模式》
网友评论