前面我们设计了员工的工资,奖金,福利系统。今天客户又来增加需求了:"我们需要统计公司,部门,或者小组的薪资成本。"得到了需求,我们还是按照老套路来完成我们的设计。
(声明:本系列所用的模式都来自GOF23中,本系列并不是讲23种经典设计模式,而是如何去使用这些模式)
前面我们设计了员工的工资,奖金,福利系统。今天客户又来增加需求了:"我们需要统计公司,部门,或者小组的薪资成本。"得到了需求,我们还是按照老套路来完成我们的设计。
1.分析
我们用"名词分析法"来分析需求里面的类(第一篇有讲解),薪资的部分我们已经有了,需求中包含公司,部门,小组这三个名词。好的我们来过滤它。
2.过滤
好,我们通过分析得到了公司,部门,小组。这里要考虑以后可能有的变化,最常见的是公司去添加一个层级,比如添加一个分公司。我们不能把公司,部门,小组,分别当成一个类来处理,这样添加层级的时候,我们又要重新写代码,然后编译发布,这是我们要极力避免的。那么怎么去做呢?其实说白了,公司的组织结构都是由Person组成的,一个树形结构。我们可以把它们统一起来,让客户程序在使用公司,部门,小组,或者人的时候具有统一性。那么我们就设计一个类就足够了。
3.设计
我们来看客户的话:"我们需要统计公司,部门,或者小组的薪资成本",也就是说我们的这个类可能要维护一个人员的列表,然后把它们的工资,福利加起来最后生成一个组织的薪资成本.需要考虑的是很有可能一个人不属于任何部门,也就是说他和公司平级,或者不属于任何小组,他和部门平级,所以这里我们对待组织和对待人必须要一样,否则我们只能去遍历判断这个节点下到底是个组织还是员工。总结一下我们的设计意图:我们希望形成一个树层次结构,而且要让组织的操作和人员的操作一样。怎么做??
GOF23中的Composite(组合):将对象组合成树形结构以表示“部分-整体”的层次结构。使得用户对单个对象和组合对象的使用具有一致性。 与我们的意图相符,OK,就是它,我们开始具体设计吧!
4.类图(为了回顾前面的设计,这次贴出设计全部类图,本篇的设计看红色框起来的部分)
我们设计了一个接口Icomposite,并且让Person,PersonComposite继承自它
代码:
Icomposite,Composite:
Code
public interface IComposite
{
double GetShouldpaid();
}
public class PersonComposite :IComposite
{
private ArrayList composite=new ArrayList(); //维护一个Icomposite的列表
public void AddComposite(IComposite com)
{
composite.Add(com); //添加一个Icomposite的子类
}
public void RemoveComposite(IComposite com)
{
composite.Remove(com); //删除一个Icomposite 的子类
}
public double GetShouldpaid()
{
double x=0;
for (int i = 0; i < composite.Count; i++) //遍历当前维护的Icomposite的列表
{
IComposite com = (IComposite)composite[i];
x += com.GetShouldpaid(); //递归到当前列表i元素的GetShouldpaid
}
return x;
}
}
Person:
Code
public abstract class AbstractPerson :IComposite
{
protected string _personName; //员工姓名
protected Salary _personSalary; //员工工资
public string PersonName
{
get { return _personName; }
set { _personName = value; }
}
public Salary PersonSalary
{
get { return _personSalary; }
set { _personSalary = value; }
}
public abstract double GetShouldpaid();
}
public class Staff : AbstractPerson
{
public override double GetShouldpaid() //实现具体的Staff的工资
{
return _personSalary.GetShouldpaid();
}
}
public class Internship : AbstractPerson
{
public override double GetShouldpaid() //实现实习者的工资
{
return _personSalary.GetShouldpaid();
}
}
客户代码:
Code
class Program
{
static void Main(string[] args)
{
StaffAndSalaryFactory saf = new StaffAndSalaryFactory(); //实例化工厂
AbstractPerson staff1 = saf.GetPerson(); //创建员工
staff1.PersonName = "涵舍愚人1";
staff1.PersonSalary = saf.GetSalary();//创建员工工资
staff1.PersonSalary.Salaryprize = BadPrize.badPrize;//使用单件初始化员工工资的绩效部分
//该员工工资为:6000+绩效3000=9000
AbstractPerson staff2 = saf.GetPerson(); //创建员工
staff2.PersonName = "涵舍愚人2";
staff2.PersonSalary = saf.GetSalary();//创建员工工资
staff2.PersonSalary.Salaryprize = GoodPrize.goodPrize;//使用单件初始化员工工资的绩效部分
//该员工工资为:6000+绩效6000=12000
PersonComposite pc1 = new PersonComposite();
pc1.AddComposite(staff1); //将Staff1加到小组PC1
PersonComposite pc2 = new PersonComposite();
pc2.AddComposite(pc1); //将PC1小组加到部门PC2
pc2.AddComposite(staff2);//将Staff2加到部门PC2
Console.Write("部门工资开支为:"+pc2.GetShouldpaid());//察看部门PC2的开支
Console.Read();
}
}
输出结果:
Composite模式和前面使用的Decorator模式大体上是一样的,对他们的父类都有一个Has-a(拥有)的关系,同时又是Is-a,所以Decorator可以无限添加功能,而Composite也可以无限添加节点,只因它们是同根生...唯一的区别就是:Composite是维护父类列表,Decorator维护了一个父类(其实就是他自己).
OK,这样我们完成就了用户的需求,但是还有一些不足,下一篇我们来完善它.
下一篇:如何使用设计模式来构造系统--(6)