## 一、装饰模式概述
装饰模式的用途,顾名思义,现实生活中我们需要一些装饰品来装饰人,或者物。淡然没有这些装饰,物体和人依然是存在的,这就意味着装饰品并非必须的,我们有时需要一个(项链),或许有时需要二个(项链,耳钉),再或者需要更多(项链,耳钉,戒指……),用一句话概括:装饰模式就是**动态地给一个对象添加一些额外的职责**。
关于更多装饰模式理论:详见博客:[装饰模式——结构型设计模式之四](http://blog.csdn.net/wangyongxia921/article/details/8480229)
## 二、用户装饰模式来装饰机房收费系统登陆
任何一个系统登陆都需要经过验证,这里以机房收费系统为例进行说明。
首先登陆到一个系统,为了系统安全性,我们应该从用户名,密码,来考虑。
登陆系统时需要提供匹配的用户名和密码,然后通过系统的验证通过后,方可登陆成功。
先要验证用户名,是否存在,然后验证用户密码是否正确,如果有登陆状态,最后验证登陆状态是否可以登陆。
在这里,我们可以把用户名,密码,登陆状态看成四对“登陆这个对象”的装饰,使用装饰模式。
先看装饰模式的类图:
![](https://box.kancloud.cn/2016-02-18_56c5ce724b74f.png)
然后结合登陆使用的装饰模式图如下:
![](https://box.kancloud.cn/2016-02-18_56c5ce753a2e1.jpg)
这里省略掉了接口:component。因为这里的concreteComponent只有“login ”,所以没有必要在定义一个接口。我们让TestUser 继承Login 类,其实,TestUser ,也不可以不继承Login ,这样,“Login ”和TestUser 之间就是关联关系,也可以实现。
具体代码实现:
Login类的如下:定义了一个抽象方法
~~~
Public MustInherit Class Login
''' <summary>
''' 检测用户是否可以登陆
''' </summary>
''' <param name="useren">用户类</param>
Public MustOverride Function TestLogin(ByVal useren As UserEntity) As Boolean
End Class
~~~
TestUser 类如下;
~~~
''' <summary>
''' 检测用户类_继承自login 类
''' </summary>
Public MustInherit Class TestUser
Inherits Login
Public declogin As Login
''' <summary>
''' 设定要装饰的对象
''' </summary>
''' <param name="declogin"></param>
''' <remarks></remarks>
Public Sub SetObject(ByVal declogin As Login)
Me.declogin = declogin
End Sub
''' <summary>
''' 检测用户是否可以登陆
''' </summary>
''' <param name="useren">用户类</param>
Public Overrides Function TestLogin(ByVal useren As UserEntity) As Boolean
'定义返回值
Dim flag As Boolean = False
'如果要装饰的对象不为空,就调用装饰方法
If Not (declogin Is Nothing) Then
flag = declogin.TestLogin(useren)
End If
Return flag
End Function
End Class ' TestUser
~~~
三个装饰类:
~~~
''' <summary>
''' 判断用户是否存在
''' </summary>
Public Class UserExist
Inherits BLL.TestUser
''' <summary>
''' 检测用户是否可以登陆_用户是否存在
''' </summary>
''' <param name="useren">用户类</param>
Public Overrides Function TestLogin(ByVal useren As UserEntity) As Boolean
'定义返回值
Dim flag As Boolean = False
Dim af As AbstractFactory.AbstractFactory = AbstractFactory.AbstractFactory.GetInstance()
Dim iuser As IDAL.IUser
'创建接口库
iuser = af.CreateUser()
If Not (iuser.QueryUserInfo(useren) Is Nothing) Then
flag = True
Else
Throw New Exception("用户名不存在,请检查用户名,重新登陆。")
End If
Return flag
End Function
End Class ' UserExist
~~~
~~~
''' <summary>
''' 验证密码是否正确
''' </summary>
Public Class TestPwd
Inherits BLL.TestUser
''' <summary>
''' 检测用户是否可以登陆_检测密码
''' </summary>
''' <param name="useren">用户类</param>
Public Overrides Function TestLogin(ByVal useren As UserEntity) As Boolean
'定义返回值
Dim flag As Boolean = False
Dim af As AbstractFactory.AbstractFactory = AbstractFactory.AbstractFactory.GetInstance()
Dim iuser As IDAL.IUser
'创建接口库
iuser = af.CreateUser()
If iuser.QueryUserInfo(useren).P_password = useren.P_password Then
flag = True
Else
Throw New Exception("登陆密码不正确,请重新输入。")
End If
Return flag
End Function
End Class ' TestPwd
~~~
~~~
''' <summary>
''' 查询用户状态
''' </summary>
Public Class UserState
Inherits TestUser
''' <summary>
''' 检测用户是否可以登陆——查询用户状态
''' </summary>
''' <param name="useren">用户类</param>
Public Overrides Function TestLogin(ByVal useren As UserEntity) As Boolean
'定义返回值
Dim flag As Boolean = False
Dim af As AbstractFactory.AbstractFactory = AbstractFactory.AbstractFactory.GetInstance()
Dim iuser As IDAL.IUser
'创建接口库
iuser = af.CreateUser()
If iuser.QueryUserInfo(useren).P_userstatus = "离线" Then
flag = True
Else
Throw New Exception("用户已经在线,不可以重复登陆。")
End If
Return flag
End Function
End Class ' UserState
~~~
主要的类都写完了,接下来就是客户端的调用了,
在调用是,根据装饰模式的特性,我们需要循环嵌套调用,为了使装饰的东西先后顺序稳定,
~~~
''' <summary>
''' 用户登陆系统方法
''' </summary>
''' <param name="useren">要登陆的用户实体</param>
Public Function Login(ByVal useren As UserEntity, worklogen As WorkLogEntity) As Boolean
Dim flag As Boolean = False
'判断用户是否存在
Dim Bqueryuser As New BLL.QueryUser
'定义登陆变量,存放用户登陆的几种情况
'Dim intLogin As Int32
'intLogin = Bqueryuser.UserInfo(useren)
'判断登陆的情况
'**************?????考虑使用迭代器模式
'使用装饰模式
'定义B层装饰模式对象
Dim Blogin As BLL.Login
'装饰对象声明
Dim BuserState As New BLL.UserState()
Dim BtestPWD As New BLL.TestPwd()
Dim BuserExist As New BLL.UserExist()
'Dim BtestUser As BLL.TestUser
'装饰过程
'4/声明验证对象
BuserState.SetObject(Blogin)
'3状态验证
BtestPWD.SetObject(BuserState)
'2密码验证
BuserExist.SetObject(BtestPWD)
'1验证用户是否存在
'验证全部通过,然后修改用户状态和插入工作记录
If BuserExist.TestLogin(useren) Then
'调用B层方法
If Buser.UpdateUserState(useren) Then
'声明工作记录对象
Dim Bworklog As New BLL.WorkLog
'调用B层方法
If Bworklog.AddWorkLog(worklogen) Then
'插入记录成功返回真
flag = True
Throw New Exception("用户登陆成功,马上跳转到主界面!")
End If
End If
End If
Return flag
End Function
~~~
通过以上的叙述,装饰模式就结束了。
如果用户需求发生变化,你需要增加价差,或者减少检查,只需要增加/去掉相应类即可,然后再客户端中修改调用对象即可。
- 前言
- 抽象工厂——创建型设计模式一
- 工厂三姐妹——创建型设计模式之二
- 初识面向对象设计模式
- 建造者模式——创建型模式之三
- 原型模式——创建型设计模式四
- 适配器 and 组合模式——结构性模式之一
- 桥接模式——结构性设计模式之二
- 组合模式——结构型设计模式之三
- 装饰模式——结构型设计模式之四
- 外观模式——结构型设计模式之五
- 代理模式——结构型设计模式之六
- 观察者模式——行为型设计模式之五
- 模板设计——行为设计模式之一
- 命令模式——行为设计模式之二
- 状态模式——行为型设计模式之三
- 职责模式——行为设计模式之四
- 中介模式——行为模式之六
- 策略+简单工厂 实战篇
- 看观察者怎么全方位观察机房收费系统
- 登陆也需要装饰——机房收费系统装饰模式实战
- 何为抽象?你有本末倒置吗?
- 再回首,策略、简单工厂是否依然?
- 再回首——行为型设计模式