外观模式由误解到理解(登录窗体为例)

起因

       设计模式在运用中愈加明白,在交流中不断提升,在敲机房个人重构的时候,外观模式和抽象工厂模式是肯定要用到的就是为为了进行解耦,当时并不理解外观模式究竟是起到怎样的一个模式,就借鉴着开始了,到了后来发现整个外观模式已经被架空了,毫无起到解耦的作用,对于书上的理论还是无法理解,无意中在交流中看到了鑫超哥的代码,恍然大悟书上的理论也明白了,下面便是自己的一些收获

上图


是什么

定义:为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用。具体的理解以代码说明,不过这两句话可以在理论上起到帮助

1.Facade为子系统提供一个对外的共同接口;2.客户端通过这个接口去读取子系统中的数据资源(在机房收费中数据资源就是B层中的方法来获取具体信息的)

作用

1.facade模式最大的作用的就是解耦分层,这样客户端虽然不知道具体的用到了facade中哪个子系统的方法数据,但不影响功能的实现,这既简便也符合开放封闭原则

2.在添加新的逻辑判断时U层可以完全解放,只需在B层定义个方法来供facade接受,如等我们登录时还需要将用户相关信息放到正在值班教师表中,我们只需把U层的相关信息传入在facade加一个update就可以了,具体的实现就交给B层了

UML图

没用facade模式之前的图




子系统修改客户端也得进行相关修改,而且客户端还要不断考虑是否应该调用该子系统

用了facade模式的UML



这时我们发现无论子系统在怎么复杂,客户端只需要调用一个外观层就够了,具体的逻辑功能的实现与判断只需子系统工作完后放到facade层就可以了

实例UML(机房收费登录窗体)



可以看到当登录时要判断是否为空,是否存在,是否密码正确,在U层只需调用facade中的checkInput足以,至于具体的逻辑判断都在B层进行的,然后将结构返回到facade,这时调用了facade的U层便可以显示结果了

如何用

当一个功能的实现要经过N多个小逻辑前提的实现才能满足的时候就可以考虑该模式了,如上机时,要判断卡号是否存在,是否正在是否还在使用,余额是否够用,是否正在上机等才能进行ONline,这是用facade模式写一个Online这个方法U层只需把cardInfo信息传过来就可以了。如果一个功能就只需满足一个条件如正在值班教师只要表里有数据就行这是就没有必要用外观模式了

理论上的使用条件:

(1)设计初期阶段,应该有意识的将不同层分离,层与层之间建立外观模式。
(2) 开发阶段,子系统越来越复杂,增加外观模式提供一个简单的调用接口。
(3) 维护一个大型遗留系统的时候,可能这个系统已经非常难以维护和扩展,但又包含非常重要的功能,为其开发一个外观类,以便新系统与其交互。

误区

以修改密码为例
<span style="color:#333333;">'U层
Private Sub btnOk_Click(sender As Object, e As EventArgs) Handles btnOk.Click
        '进行非空判断
        If txtPassWord.Text = "" Then
            MsgBox("旧密码不能为空")
            txtPassWord.Focus()
            Exit Sub
        End If
        If txtNewPassWord.Text = "" Then
            MsgBox("新密码不能为空")
            txtNewPassWord.Focus()
            Exit Sub
        End If

        '对新密码进行限定只能是数字
        If IsNumeric(txtNewPassWord.Text) = False Then
            MsgBox("请输入数字")
            txtNewPassWord.Text = ""
            txtNewPassWord.Focus()
            Exit Sub
        End If

        '判断旧密码是否正确
       </span><span style="color:#ff0000;"> Dim ModifyFAC As New Facade.LoginFAC '借用了登录窗体的密码判断的代码
        Dim UserInfo As New Entity.EntityUsersWork

        UserInfo.userID = frmLogin.txtUserName.Text</span><span style="color:#333333;">
        Dim table As New DataTable
        table = ModifyFAC.loginInfo(UserInfo)
        If txtPassWord.Text = Trim(table.Rows(0).Item(1)) Then
            MsgBox("旧密码正确")
        Else
            MsgBox("旧密码错误")
            txtPassWord.Text = ""
            txtPassWord.Focus()
            Exit Sub
        End If

        '判断两次密码是否一样
        If txtNewPassWord.Text <> txtNew1.Text Then
            MsgBox("两次密码不一致请重新确认")
            txtNew1.Text = ""
            txtNew1.Focus()
            Exit Sub
        Else
            '进行密码更新
            Dim updateFAC As New Facade.ModifyFAC
            Dim table1 As New Boolean
            UserInfo.pwd = txtNew1.Text
           </span><span style="color:#ff0000;"> table1 = updateFAC.ModifyPwd(UserInfo)</span><span style="color:#333333;">
            MsgBox("修改成功")
        End If
End Sub


'Facade层
</span><span style="color:#ff0000;">Public Function ModifyPwd(ByVal UserInfo As Entity.EntityUsersWork) As Boolean</span><span style="color:#333333;">
        Dim ModifyBLL As New ModifyPwdBLL
        Dim table As New Boolean
        '定义一个方法引用B层
        table = ModifyBLL.ModifyPwd(UserInfo)
        Return table
    End Function
</span>
        如果单纯的从实现代码功能来看,这段代码是没有任何问题的,然而仔细看后就会发现,我用了facade层之后不仅没有实现解耦,还令U层与facade层,facade层与B层紧密的链接在了一起,和U层直接调用B层没有区别。而且我还调用了其他功能的方法,使得层与层,功能与功能之间混乱了

正常用facade层应该是为多个小功能的判断整合成一个大的接口供U层调用,所以我陷入的误区便是仅仅把Facade层理解成了U层和B层的过度层,而不死解耦层,即令U层和Facade层紧密结合,Facade层和U层紧密结合,U层和层不是解耦而是没有关系了。(主要看红色的代码)

正解实例

以登录窗体为例

<span style="color:#333333;">U层
   Private Sub btnOK_Click(sender As System.Object, e As System.EventArgs) Handles btnOK.Click

        Try
            Dim facade As New Facade.LoginFacade
            Dim UserInfo As New Model.LoginUserInfo

            UserInfo.UserName = txtUser.Text.Trim
            UserInfo.Password = txtPassword.Text
            Model.LoginUserInfo.User = txtUser.Text.Trim



            Dim strCheckResult As String
            </span><span style="color:#ff0000;">strCheckResult = facade.CheckInput(UserInfo)'通过checkInput将信息传入就静待其变了,不用去考虑是怎么实现的</span><span style="color:#333333;">


            If strCheckResult = "OK" Then
                MsgBox("你可以成功登陆啦~~~", MsgBoxStyle.OkOnly, "来自软件欢乐的提示       ")
                Dim frmmain As New frmMain
                frmmain.Show()

            Else
                Call ClearTxt()
                MsgBox(strCheckResult, MsgBoxStyle.OkOnly, "来自软件热心的提示       ")
            End If

        Catch ex As Exception
            MsgBox("UI层-登陆窗体 出现错误啦~~~~")
            Call ClearTxt()
        End Try

    End Sub

Facade层

 Public Function CheckInput(ByVal UserInfo As Model.LoginUserInfo) As String

        </span><span style="color:#ff0000;">Dim Checker As New BLL.LoginBll'具体的实现就交给了B层去判断了,并把判断结果返回到Facade层</span><span style="color:#333333;">
        Dim result As String
        Dim result1 As String
        Dim result2 As String
        Dim result3 As String

       </span><span style="color:#ff0000;"> result1 = Checker.IsNothing(UserInfo)
        result2 = Checker.CheckUser(UserInfo)
        result3 = Checker.CheckPassword(UserInfo)
        result = Checker.GetAnswer(result1, result2, result3)
        Return result</span><span style="color:#333333;">

    End Function
</span>
此处说明一点:一般我们都是传实体,返回的有table型,boolean型,泛型。当乍一看到string时有点蒙,其实传什么型的参数和要返回什么的数据是没有什么直接关系的,只要根据需要做好判断和转化就行

总结

      关于外观模式学习一开始没有了解参考别人的也断章取义导致完全用错,在交流中及时发现了错误明白了Facade模式是为多个子系统提供一个统一的接口,如何功能并不复杂而不必考虑此模式



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 25
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值