您的位置:首页 > 其它

如何使用设计模式来构造系统--(2)

2011-09-09 17:50 696 查看
(由于篇幅有限,部分代码请看如何使用设计模式来构造系统--(1) )

上一篇我们分析了员工,工资,以及绩效奖金三个类,并且使用了Bridge和Stratege两种模式,对他们之间的组合和行为进行了设计,但是我们的设计并不完善。我们知道员工的基本工资可能每年都不一样,甚至有可能随时地根据公司的制度发生变化,而设计的根本意图就是去封装变化,让我们的系统更加的长寿,不会因为变化而大量的重造,我们怎么去避免工资变化时,员工类不改变呢??

先看一下,上次设计的员工类的代码:



public abstract class AbstractPerson

{

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(IPrize prize);

}

public class Staff : AbstractPerson

{

public override double GetShouldpaid(IPrize prize)

{

_personSalary = new SttafSalary(); //初始化正式员工的基本工资

_personSalary.Salaryprize = prize; //赋予绩效

return _personSalary.GetShouldpaid();

}

}

这里我们看到在初始化员工工资时出现了new SttafSalary(),这就使Person与SttafSalary产生了紧耦合,也就是说SttafSalary的变化会影响Person类的稳定。那么使用何种设计模式来封装这种创建时的变化呢?

GOF23中的Factory Method(工厂方法): 定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。

工厂方法的意图和我们要封装的变化意图相同,那么我们就用它来设计吧,看看类图:



我们使用两个同接口的工厂来封装创建时的变化,这样你在各个工厂中去添加或修改你的业务都不会影响到Person,当然原来的那种直接new的方法也不会改变,但是当你的员工类包含的工资类发生变化时(比方说现在InterShip的工资升级为正式员工的工资,而正式员工的工资重新定义),就不能应对变化了,但是将创建工作封装到Factory,就可以避免这种变化引起的Person类的修改,而只需要去添加Salary的子类,修改Factory的子类,就可以完成了。

我们来看代码。

工厂部分的实现:



public abstract class SalaryFactory

{

public abstract Salary GetSalary(); //留给具体某种工资福利制度工厂去实现

}

public class StaffSalaryFactory:SalaryFactory

{

public override Salary GetSalary() //具体某种工资福利制度工厂

{

return new SttafSalary();

}

}

public class InternshipSalaryFactory:SalaryFactory

{

public override Salary GetSalary() //具体某种工资福利制度工厂

{

return new InternshipSalary();

}

}

Person类的实现:



public abstract class AbstractPerson

{

#region 字段

protected string _personName; //员工姓名

protected Salary _personSalary; //员工工资

#endregion

#region 属性

public string PersonName

{

get { return _personName; }

set { _personName = value; }

}

public Salary PersonSalary

{

get { return _personSalary; }

set { _personSalary = value; }

}

#endregion

public abstract double GetShouldpaid(IPrize prize);

}

public class Staff : AbstractPerson

{

public override double GetShouldpaid(IPrize prize)

{

_personSalary = new StaffSalaryFactory().GetSalary();

_personSalary.Salaryprize = prize;

return _personSalary.GetShouldpaid();

}

}

public class Internship : AbstractPerson

{

public override double GetShouldpaid(IPrize prize)

{

_personSalary = new InternshipSalaryFactory().GetSalary();

_personSalary.Salaryprize = prize;

return _personSalary.GetShouldpaid();

}

}

OK,这样我们就完成了这种变化的封装。在实际项目中你可以把Person中创建具体那个工厂,在配置文件中存储,然后做个Switch ,就可以让他们的结合更松散了,这里就不多说了。

接下来我们还有一个问题,Prize绩效的制度,上一篇的设计,每一个员工的工资都会创建一个Prize,而Prize只是固定的制度,员工都是遵守和共享这个制度的,这样就造成了内存的浪费,怎么去解决这个问题呢,让系统中只存在我们想要的固定数目的Prize的实例呢?

Singleton(单件):保证一个类仅有一个实例,并提供一个访问它的全局访问点。和我们的意图一样,那就用它吧。



public interface IPrize

{

double GetPrize(Salary salary);

}

public class BadPrize : IPrize //绩效不好的奖金比率

{

public static readonly BadPrize badPrize = new BadPrize(); //在这里使用静态只读,做到badPrize不可被修改

private BadPrize()//在这里使用私有构造,做到BadPrize类不可被实例化

{ }

public double GetPrize(Salary salary)

{

return salary.SalaryNum * 0.5; //干的不好奖金扣一半

}

}

public class GoodPrize : IPrize //绩效好的奖金比率

{

public static readonly GoodPrize goodPrize = new GoodPrize();

private GoodPrize()

{ }

public double GetPrize(Salary salary)

{

return salary.SalaryNum * 1; //干的好奖金全发,哈哈

}

}

这样我们就保证了,在系统运行时BadPrize和GoodPrize都只有一个实例,完成了我们的设计。

现在来看看调用程序:



class Program

{

static void Main(string[] args)

{

Staff staff = new Staff();

staff.PersonName="涵舍愚人";

Console.Write(staff.PersonName + "本月实发工资为" + staff.GetShouldpaid(BadPrize.badPrize)); //由原先的new BadPrize(),变为现在的单件badPrize

Console.Read();

}

}

输出结果:



由于这个月干的不好,绩效工资被扣一半.....:(

我们使用了两种设计模式Factory Method和Singleton ,来封装了员工的工资创建和绩效工资的单件,好了这样我们就设计完成了用户的需求,下一篇中可恶的客户要添加需求了。。(在实际开发中这种事情的发生频率,地球上的程序员都知道啦。)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: