【手写源码-设计模式8】-组合模式-基于项目提成分配场景模拟

1:主题拆解

①基本介绍

②项目提成分配场景模拟

③安全组合模式升级

④组合模式的优缺点

⑤适用场景

⑥不想做CEO的实习生不是好开发

2:基本介绍

 组合模式,将对象组合成树形结构以表示“整体-部分”的层次结构,一种对象结构型模式。

由于在软件开发中存在大量的树形结构,因此组合模式是一种使用频率较高的结构型设计模式,在XML解析、组织结构树处理、文件系统设计等领域,组合模式都得到了广泛应用。

组合模式的分类:

①透明组合模式

透明组合模式中,抽象构件角色中声明了所有对于管理成员对象的方法,透明组合模式是组合模式的标准形式。

②安全组合模式

安全组合模式中,在抽象构件角色中没有声明任何用于管理成员对象的方法,而是在容器构件类中声明并实现这些方法。

3:项目提成分配场景模拟

1:项目背景

公司承包了一个100万的项目,今天是项目完客户支付尾款的第一天,作为参与这个大项目的实习生“阿发”,有幸的成为了项目提成的成员,突然感觉莫名的激动。

2:提成分配表

 3:透明组合模式

①定义部门/个人抽象基类

    public abstract class AbstractDomain
    {
        public string Name { get; set; }
        public double Percent { get; set; }
        public abstract void Commission(double total);
        public abstract void AddChild(Domain domainChild);
    }

②具体部门实现

public class Domain : AbstractDomain
{
    private List<Domain> DomainChildList = new List<Domain>();
    public override void AddChild(Domain domainChild)
    {
        this.DomainChildList.Add(domainChild);
    } 
    public override void Commission(double total)
    {
        double result = total * this.Percent / 100;
        Console.WriteLine("this {0} 提成 {1}", this.Name, result);


        foreach (var domainChild in DomainChildList)
        {
            domainChild.Commission(result);
        } 
    } 
}

③构建提成关系

private static Domain BuildTree()
{
    Domain domain = new Domain()
    {
        Name = "待分配",
        Percent = 10
    };
    #region
    Domain domain1 = new Domain()
    {
        Name = "CEO",
        Percent = 30
    };
    Domain domain2 = new Domain()
    {
        Name = "各部门共有",
        Percent = 70
    };


    Domain domain21 = new Domain()
    {
        Name = "实施",
        Percent = 20
    };
    Domain domain22 = new Domain()
    {
        Name = "测试",
        Percent = 10
    };
    Domain domain23 = new Domain()
    {
        Name = "销售",
        Percent = 30
    };
    Domain domain24 = new Domain()
    {
        Name = "开发",
        Percent = 40
    };
    Domain domain241 = new Domain()
    {
        Name = "经理",
        Percent = 20
    };
    Domain domain242 = new Domain()
    {
        Name = "主管",
        Percent = 15
    };
    Domain domain243 = new Domain()
    {
        Name = "开发团队",
        Percent = 65
    };
    Domain domain2431 = new Domain()
    {
        Name = "项目组1",
        Percent = 50
    };
    Domain domain2432 = new Domain()
    {
        Name = "项目组2",
        Percent = 50
    };
    Domain domain24321 = new Domain()
    {
        Name = "项目经理",
        Percent = 20
    };
    Domain domain24322 = new Domain()
    {
        Name = "开发人员",
        Percent = 80
    };
    Domain domain243221 = new Domain()
    {
        Name = "高级开发人员",
        Percent = 40
    };
    Domain domain243222 = new Domain()
    {
        Name = "中级开发人员",
        Percent = 30
    };
    Domain domain243223 = new Domain()
    {
        Name = "初级开发人员",
        Percent = 20
    };
    Domain domain243224 = new Domain()
    {
        Name = "实习生",
        Percent = 10
    };
    Domain domain2432241 = new Domain()
    {
        Name = "实习生1",
        Percent = 25
    };
    Domain domain2432242 = new Domain()
    {
        Name = "实习生2",
        Percent = 25
    };
    Domain domain2432243 = new Domain()
    {
        Name = "实习生3",
        Percent = 25
    };
    Domain domain2432244 = new Domain()
    {
        Name = "阿发",
        Percent = 25
    };
    domain243224.AddChild(domain2432241);
    domain243224.AddChild(domain2432242);
    domain243224.AddChild(domain2432243);
    domain243224.AddChild(domain2432244);


    domain24322.AddChild(domain243221);
    domain24322.AddChild(domain243222);
    domain24322.AddChild(domain243223);
    domain24322.AddChild(domain243224);


    domain2432.AddChild(domain24321);
    domain2432.AddChild(domain24322);


    domain243.AddChild(domain2431);
    domain243.AddChild(domain2432);


    domain24.AddChild(domain241);
    domain24.AddChild(domain242);
    domain24.AddChild(domain243);


    domain2.AddChild(domain21);
    domain2.AddChild(domain22);
    domain2.AddChild(domain23);
    domain2.AddChild(domain24);


    domain.AddChild(domain1);
    domain.AddChild(domain2);
    #endregion
    return domain;
}

 ④上端调用

double total = 1000000;
Domain domain = BuildTree();
domain.Commission(total);

分析:此时就已经现实了项目提成的分配。由于抽象基类中声明了所有对于管理成员对象的方法,即为透明组合模式。

4:安全组合模式升级

经过分析可以发现叶子节点其实是没有AddChild的方法,也没有子节点。此时可以对最后一级叶子节点进行修改。

①抽象基类中去掉AddChild方法

    public abstract class AbstractDomain
    {
        public string Name { get; set; }
        public double Percent { get; set; }
        public abstract void Commission(double total); 
    }

②非叶子节点,即容器继承基类并且实现

public class Domain : AbstractDomain
{
    private List<Domain> DomainChildList = new List<Domain>();
    public void AddChild(Domain domainChild)
    {
        this.DomainChildList.Add(domainChild);
    } 
    public override void Commission(double total)
    {
            
        double result = total * this.Percent / 100;
        Console.WriteLine("this {0} 提成 {1}", this.Name, result);


        foreach (var domainChild in DomainChildList)
        {
            domainChild.Commission(result);
        } 
    } 
}

③叶子节点继承并且实现

    public class DomainLeaf : AbstractDomain
    {
        public override void Commission(double total)
        {
            double result = total * this.Percent / 100;
            Console.WriteLine("this {0} 提成 {1}", this.Name, result);
        } 
    }

④构建提成关系与上端调用不变

分析:此为安全组合模式,为何称为安全组合模式,在抽象构件角色中没有声明任何用于管理成员对象的方法,即没有定义AddChild方法。并且叶节点也没有此方法。

5:组合模式优缺点

1:优点

①层次控制

组合模式可以清楚定义分层次的复杂对象,表示对象的全部或者部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制

②一致使用构件

客户端可以一致地使用容器构件或者叶子构件,也就是能针对构件抽象层一致性编程

③扩展性好

增加新的容器构件或者叶子构件都很方便,符合开闭原则

④有效针对树形结构

组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子构件与容器构件的递归组合,可以形成复杂的树形结构,但控制树形结构却很简单

2:缺点

①难以限制构件类型

增加新构件时难以限制构件类型,比如希望容器构件中只有某一特定类型的叶子构件,例如一个只能包含图片的文件夹,使用组合模式时不能依赖类型系统来施加这些约束,需要再运行时进行类型检查来实现,过程较为复杂。

6:适用场景

①具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致性对待它们。

②处理树形结构,例如电脑文件夹,部门组织架构,学校组织架构。

③系统中能够分离出叶子构件以及容器构件,而且类型不固定,需要增加新的叶子构件或者容器构件。

④使用场景不是很丰富,一般都是通过数据库中的ParentID来实现的树形结构。

7:不想做CEO的实习生不是好开发

理想很美好,现实很骨干,一个100万的项目兴致勃勃参与分提成只分到了182块。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不要迷恋发哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值