装饰模式: 主要用来实现动态的添加功能。这样可以使得在需要新的方法时可以直接的添加新的类,主类保持不变,符合设计模式中“开放封闭原则”。
在机房收费的系统用户登录的过程中,可以使用装饰模式。在登录的时候我们分别需要验证用户名,密码,如果要求一个用户只能够登录一次,还需要验证用户的登录状态,如果都没有问题则用户进如系统的主界面。这里的“验证用户状态”就可以看做动态的功能,需要的时候就动态的加载上。
首先以机房中的登录为例看一下装饰模式的类图。
LogingBLL就是要被装饰的主类,TestUserBLL是装饰类的抽象类,继承和实现LoginBLL的TestLogin方法,增加SetObject方法用来设置要装饰的对象。其他的三个类TestLoginStateBLL、UserExistBLL、TestLoginPWDBLL继承TestUserBLL类同时重写其中TestLogin方法。代码的实现如下:
public class LoginBLL<span style="white-space:pre"> </span>//要被装饰的对象
{
public LoginBLL()
{
}
/// <summary>
/// 检测用户是否可以登陆,抽象方法,必须重写
/// </summary>
/// <param name="enUser"></param>
public virtual bool TestLogin(UserModel enUser)//需要被继承重新的方法
{
return true;
}
}
public class TestUserBLL:LoginBLL<span style="white-space:pre"> </span>//继承LoginBLL这个要被装饰的类
{
protected LoginBLL declogin;//实例一个要被装饰的对象
public TestUserBLL() {
}
public TestUserBLL(UserModel enUser)
{
}
public void SetObject(LoginBLL declogin){<span style="white-space:pre"> </span>//该方法设置要装饰的对象
this.declogin = declogin;
}
/// <summary>
/// 检测用户是否可以登陆
/// </summary>
/// <param name="enUser"></param>
public override bool TestLogin(UserModel enUser)<span style="white-space:pre"> </span>//重新TestLogin,实质执行的是declogin的TestLogin方法
{
try
{
if (declogin != null)
{//如果要装饰的对象不为空就调用被装饰对象的TestLogin方法进行检测
return declogin.TestLogin(enUser);
}
else
{
return false;//如果要装饰的对象为空就直接的返回false
}
}
catch (System.Exception)
{
throw new Exception("用户登录信息错误请重新输入!");
public class TestLoginStateBLL : TestUserBLL<span style="white-space:pre"> </span>//继承TestUserBLL重新TestLogin方法,主要用来检验要登录的用户的状态
{
public TestLoginStateBLL(){
}
/// <summary>
/// 检测用户是否可以登陆——查询用户状态,已经登录返回false,抛出异常提示:用户已经在线,不可以重复登陆。未登录返回true。
/// </summary>
/// <param name="enUser"></param>
public override bool TestLogin(UserModel enUser){
bool flag = false;
try
{
base.TestLogin(enUser); //先运行原来TestUserBLL的TestLoging,在执行自己的如下的方法
CreateFactory factory = new CreateFactory();
IUser userInter = factory.CreateUser();
if (userInter.QueryById(enUser) ==true)<span style="white-space:pre"> </span>//调用B层相关方法进行检验
{
flag = true;
}
else {
throw new Exception("用户已经在线,不可以重复登陆");<span style="white-space:pre"> </span>//检验失败则抛出错误
}
}
catch (System.Exception)
{
throw new Exception("用户不存在,请重新输入用户名");
}
return flag;
}
}
public class TestLoginPWDBLL : TestUserBLL
{
/// <summary>
/// 检测用户是否可以登陆_检测密码。密码正确返回true,否则返回false,抛出异常提示:登陆密码不正确,请重新输入
/// </summary>
/// <param name="enUser"></param>
public override bool TestLogin(UserModel enUser){
bool flag = false;
try
{
base.TestLogin(enUser);
CreateFactory factory = new CreateFactory();
IUser userInter = factory.CreateUser();
if (userInter.QueryById(enUser) ==true) {
flag = true;
}else{
throw new Exception("用户不存在,请重新输入用户名");
}//没有检查密码是否正确的方法
}
catch (System.Exception)
{
throw new Exception("用户不存在,请重新输入用户名");
}
return flag;
}
}
public class UserExistBLL : TestUserBLL
{
public UserExistBLL(){
}
/// <summary>
/// 检测用户是否可以登陆_用户是否存在 ,存在返回true,否则返回false。抛出异常提示:用户名不存在,请检查用户名,重新登陆
/// </summary>
/// <param name="enUser"></param>
public override bool TestLogin(UserModel enUser){
bool flag = false;
try
{
base.TestLogin(enUser);
CreateFactory factory = new CreateFactory();//实例化工厂
IUser userInter = factory.CreateUser();//调用实例化工厂的方法实例化一个接口
if (userInter.QueryById(enUser) ==true)//通过ID检验用户是否存在
{
flag = true;
}
else {
throw new Exception("用户不存在,请重新输入用户名");
}
}
catch (System.Exception)
{
throw new Exception("用户不存在,请重新输入用户名");
}
return flag;
}
}
public bool Login(WorkModel enWork, UserModel enUser)
{
bool flag = false;
UserBLL UserBLL = new UserBLL();
LoginBLL LoginBLL = new LoginBLL(); //实例化被装饰的类
//装饰过程
<span style="white-space:pre"> </span> TestLoginStateBLL LoginStateBLL = new TestLoginStateBLL();
TestLoginPWDBLL LoginPWDBLL = new TestLoginPWDBLL();
UserExistBLL UserExistBll = new UserExistBLL();
//设置LoginStateBLL要装饰的对象
LoginStateBLL.SetObject(LoginBLL);
//设置UserExistBll要装饰的对象
UserExistBll.SetObject(LoginStateBLL);
//设置LoginPWDBLL要装饰的对象
LoginPWDBLL.SetObject(UserExistBll);
//检测用户是否存在
if (LoginPWDBLL.TestLogin(enUser) == true)//在执行LoginPWDBLL的TestLogin方法时会先执行</span>
{
//写入工作记录
WorkBLL WorkBll = new WorkBLL();
if (WorkBll.InsertOnLogin(enWork) == true)
{
flag = true;
}
}
return flag;
}
代码的实现相对容易,但是装饰模式需要注意的是其中的装饰顺序,通过时序图来理一下思路(只是装饰模式的时序图)。