梳理公司的组织架构---组合模式

cover

题外话

本来是周更的频率, 因为真实的"小光"真实地逃离了北京, 回了武汉, 回了老家, 处理了一些私人事务. 也就有快一个月时间没有更新了, 抱歉.

年终总结也都没有时间写, 抽空写这么一篇, 提前祝大家新年快乐, 过年回家路上平安顺利.

前情提要

上集讲到, 小光统一了各个分店的制作热干面的流程, 并且引入模板方法在不改变热干面的制作流程基础上可以定制其中某些步骤. 通过这些措施, 小光热干面的品牌性也是更加深入人心, 生意红红火火.

此时的小光, 有了更多的时间去思考公司的前程, 他认为, 一个良好的有序的组织架构是公司发展的必要点. 而此时, 小光也有觉得是时候梳理下公司的组织架构了.

所有示例源码已经上传到Github, 戳这里

组织架构

小光参考了当前很多公司的一些架构方式, 根据分店, 职责简单梳理了下目前小光热干面的架构:


整个就是一个树形结构.

  • 小光热干面总部下面管理着各个分店, 也有其自己的部门.
  • 各个分店也有着自己的部门.

设计一套系统来表达这个组织架构

梳理完组织关系后, 小光觉得有必要设计一套系统来管理这个关系图, 以便后续能方便的查看和管理这个架构, 并能很清晰地讲解给新员工.

简单的开始

一开始, 小光并没有想太多, 按照不同的层级, 分别创建了总公司, 分店, 部门三个类:

// 部门
public class Department {

    private String name;

    public Department(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "部门:" + name;
    }
}

// 分店
public class BranchOffice {

    private String name;

    public BranchOffice(String name) {
        this.name = name;
    }

    private List<Department> departments = new ArrayList<>();

    public void add(Department sub) {
        departments.add(sub);
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder("分公司:" + name);

        for (Department dept : departments) {
            builder.append(" - " + dept.toString());
        }

        return builder.toString();
    }
}

// 总公司
public class HeadOffice {

    private String name;

    public HeadOffice(String name) {
        this.name = name;
    }

    private List<Department> departments = new ArrayList<>();

    public void add(Department sub) {
        departments.add(sub);
    }

    private List<BranchOffice> branches = new ArrayList<>();

    public void add(BranchOffice branchOffice) {
        branches.add(branchOffice);
    }

    public void print() {
        System.out.println("总公司:" + name);
        for (BranchOffice branch : branches) {
            System.out.println(" - " + branch);
        }

        for (Department dept : departments) {
            System.out.println(" - " + dept);
        }
    }
}

利用这些层次的类来组成小光的组织架构:

public class XiaoGuang {

    public static void main(String[] args) {

        HeadOffice headOffice = new HeadOffice("小光热干面");

        Department financeDept = new Department("财务部");
        Department strategyDept = new Department("策划部");

        BranchOffice ov = new BranchOffice("光谷分店");
        ov.add(financeDept);
        ov.add(strategyDept);

        BranchOffice huashan = new BranchOffice("花山分店");
        huashan.add(financeDept);
        huashan.add(strategyDept);

        headOffice.add(financeDept);
        headOffice.add(strategyDept);
        headOffice.add(ov);
        headOffice.add(huashan);

        headOffice.print();
    }
}

结果如下, 达到要求:

总公司:小光热干面
 - 分公司:光谷分店 - 部门:财务部 - 部门:策划部
 - 分公司:花山分店 - 部门:财务部 - 部门:策划部
 - 部门:财务部
 - 部门:策划部

小光的思考

看着这新鲜出炉的架构程序, 小光总觉得哪儿不对劲儿. 毕竟小光是历经了北上广各种类型公司的人才啊, 回想起上班敲代码的日子, 小光想起了哪儿不妥了. 公司总会发展, 发展过程中总会有一些战略调整, 从而导致公司部门的各种变化.

目前小光设计的组织架构是三层架构, 但是随着公司的发展壮大, 很有可能层级会变得更多. 比如说, 总部的采购部壮大了, 可能会增加下一级的食材采购部和设备采购部. 甚至可能现在的层级还会随着公司的战略调整而升降. 例如, 如果分店开到别的城市了, 可能会在总部和分店之间插入一层"子公司"来分别管理各地的分店. 如下:


那么就出现了一个我们一直在强调的问题: 有些东西可能会一直有变化, 而我们从产品角度肯定会想要拥抱变化, 然而代码层面上我们又不想修改代码(修改原有代码意味着还有对原有逻辑负责).

那应该怎么办呢? 有没有更好的方式来表达这种树形的组织架构关系呢? 以便能够很容易地扩展层次呢?

小光又回想起了自己的码农时代, 回想当年这种问题的解决方案:

既然是因为变化, 扩展而引起的问题, 我们最重要是要先找出系统中可变不可变的部分, 封装不可变(使其修改关闭), 拥抱可变(使其扩展开放).

小光的解决之道

那么具体到这个组织系统架构的问题, 又该怎么做呢?

小光可不想每增加一个层级都要重新为其增加一个类, 然后改变原有系统. 特别是有些情况下, 曾加的类(子公司)中可能会包含分店和自己的部门. 随着类别的增加, 每次增加一个层级将会越来越难.

小光想到着, 突然想到:

每个部门/分店/子公司乃至总公司不都是部门的集合吗?
部门可能有下属部门, 可能没有
分店下有部门
子公司下有分店, 可能还有自己的部门
总公司下有子公司, 分店, 自己的部门

所以说, 所有实体(总公司/子公司/分店/部门)实际上都是由部门组成的. 这些实体也都可以看着是一个部门.

想到做到:

首先定义出基础的部门:

public class Department {

    private String name;

    public Department(String name) {
        this.name = name;
    }

    private List<Department> subDepartments = new ArrayList<>();

    public void add(Department sub) {
        subDepartments.add(sub);
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder(name);

        for (Department dept : subDepartments) {
            builder.append("\n");
            builder.append(" - " + dept.toString());
        }

        return builder.toString();
    }
}

来看下, 利用Department这一个类别怎么搭建组织:

public class XiaoGuang {

    public static void main(String[] args) {

        Department financeDept = new Department("财务部");
        Department strategyDept = new Department("策划部");

        Department ovBranchOffice = new Department("光谷分店");
        ovBranchOffice.add(financeDept);
        ovBranchOffice.add(strategyDept);

        Department huashanBranchOffice = new Department("花山分店");
        huashanBranchOffice.add(financeDept);
        huashanBranchOffice.add(strategyDept);

        Department wuhanChildOffice = new Department("武汉子公司");
        wuhanChildOffice.add(ovBranchOffice);
        wuhanChildOffice.add(huashanBranchOffice);

        Department changshaChildOffice = new Department("长沙子公司");

        Department xiaoguang = new Department("小光热干面");
        xiaoguang.add(wuhanChildOffice);
        xiaoguang.add(changshaChildOffice);
        xiaoguang.add(financeDept);
        xiaoguang.add(strategyDept);

        System.out.println(xiaoguang);
    }
}

输出如下

小光热干面
 - 武汉子公司
    - 光谷分店
        - 财务部
        - 策划部
    - 花山分店
        - 财务部
        - 策划部
 - 长沙子公司
 - 财务部
 - 策划部

输出稍有调整, 以显示直观的层级. 大家可以自行修改下代码, 来给department加入level属性, 以便输出更完美的结构.

到此, 我们算是解决了组织架构的问题了, 以后不管是增加了什么层级, 我们都只需要使用Department来表示即可, 而无需增加一个类了.

故事之后

照例, 我们来缕缕小光设计的这套系统的"类关系":


结构相当简单, 实际上就是一个类, 其中关键的是: 这个类中有一个list属性(subDepartments)包含的是一组该类. 有点递归的感觉.

这个就是我们今天想说的 --- 组合模式

组合模式
又叫部分整体模式,通过组合的方式, 创建一个包含了一组自己的对象组(List<Department>)的类(Department). 从而达成了用一个类来递归地表示一个整体.

组合模式通常用来解决树形结构的表达问题, 例如本例中的组织结构.
所谓组合的方式, 就是创建一个包含了一组自己的对象组的类


注: 我们这里实现的相对简单, 旨在说明模式的形式.
实际场景中, Department可能是一个抽象的, 例如有一个抽象方法来执行该部门的职责, 有不同的具体部门实现来实现其职责. 从而有不同的"Department实现"来组合另一个大的Department节点.

扩展阅读一

前面说到, 组合模式通常用来处理树形结构的表达问题. 而我们的用户界面实现通常就是一个UI元素的节点树. 例如HTML中的div中可能有button, 还会有其他div层级, 依次往下; Java SE中的界面实现AWT和Swing包也到处是组合模式的体现; Android中的View体系, View和ViewGroup, Layout层级树也都是组合模式的体现.

在此我们以Android的View体系为例, 简单描述下.
众所周知, Android的界面实际上就是一颗大树, Hierarchy Viewer中展示的就是一个树形结构. 我们来看下Android是怎么利用组合模式实现的.

如下:

  1. ViewGroup就是相当于例子中的Department, 这里面比我们的例子复杂的是, ViewGroup是扩展自View的, View实际上我们可以理解为是叶子节点, 也就是最小的组成单元了, 不再有以下的层级了.
  2. ViewGroup中包含了一组View对象, 因为ViewGroup是View的子类, 故而我们也可以说ViewGroup中包含了一组ViewGroup和/或View. 进入形成了我们之前说的递归, 生成一个树形结构.

关于View的体系, 在此不细述了.


搭建好弹性可扩展的组织架构体系, 小光又开始将眼光转移到市场, 转移到业务了, 准备着新年大展拳脚~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容