`

软件设计模式系列之四 门面模式(也叫外观模式,Facade) .

 
阅读更多

我们接着上篇文章来讲,上篇最后将商场收银软件确实做到程序易维护,可扩展。但是,这样就完了吗?

如果你的程序再也不修改了,或者就是改改打折的额度和返利额度,那么的代码是足够可以了。不过需求却是会不断产生的。比如说,现在这个程序是单机版的程序,如果需要商场多层楼的所有收银机都要使用,那该怎么办?
那用XML的配置文件就不合适了,应该用数据库会比较好。
C/S架构的坏处,更新麻烦,不够安全等等,他也不是傻瓜,每次更新都需要针对每台机器部署,一次就半天,那些工作时间他是需要给程序员付薪水的。所以他提出要改为B/S架构,客户端用浏览器支持,你怎么办?
那需要改界面了,把应用程序改成Web程序。

“就你现在的代码,改起来容易吗?”
“好象不容易,需要重新写,尽管可以复制一些代码过去,不过要重新写的东西还是很多的。”
“好,那你有没有发现,我说了这么多的需求变动,但系统中有一些东西一直没有变,是哪些?”
“知道,是策略模式用到的那几个类,也就是正常收费、打折消费、返利消费等算法是没有变化的。”

“是呀,其实不是算法不会变,而是之前我们已经考虑它很多了,用了策略模式,用了反射技术使得它的变化相对稳定。你刚才也说,要把应用程序改为Web是需要复制粘贴的,可实际上,改改界面和这些算法有什么关系?”
“没有关系。”
“还有,把配置文件改为数据库访问,这其实是读取写入数据的操作,和算法又有什么关系呢?”
“也没有关系,是说,他们之间完全可以分离开,互不影响,改动其一,不要影响其它两者?哦,这是不是就是所谓的三层架构?”
“所谓的三层开发,就是关于表现层、业务逻辑层和数据访问层的开发。
这其实只是大方向的分层,每个层中都有可能再细分为多个层次和结构。”


既然要改成B/S结构,那么我们应该将原来的解决方案分为三个项目:
一个UI项目,目前是WinForm的程序
一个BLL项目,用来把算法类都封装
一个DAL项目,用来访问配置文件

这时,我们就不得不提到‘迪米特法则(LoD)’ 也叫最少知识原则。

什么时候LoD呢?

简单的说,就是如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
实迪米特法则还是在讲如何减少耦合的问题,类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。也就是说,信息的隐藏促进了软件的复用。

对于我们之前的代码中,红色部分读取配置文件的代码他应该属于DAL层

之前这段代码中,我们可以清晰的看到,蓝色应该属于BLL,也就是在业务逻辑层。黑色属于UI层,也就是在表示层。

而我们希望的是,在表示层里面只要告诉系统单价和数量,然后得到结果就行。

这就像是我们要去买个电脑,现在有2种方案:

一个方案是,我们去电子市场把自己需要的配件都买回来,然后自己组装,也就是DIY(Do It Yourself)。

另一个方案是,我们去找一家专业的装机公司,我具体的要求提出来,然后等着拿电脑就好了。

第一个方案就类似我们之前做的程序,将UI,BLL,DAT 各个配件拿到一起,然后自己组装。

第二个方案就类似我们现在希望的程序,我们只需告诉系统单价和数量,系统返回我们结果就行。

第二种方案中的这个专业的装机公司,其实就相当于我们本篇博文要讲的主角 门面模式(外观模式)

什么是门面模式呢?

简单的讲门面模式(也叫外观模式)要求一个子系统的外部与其内部的通信必须通过一个统一的门面(Facade)对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。

也就相当于我们配机的第二个方案。

当然现实生活中有很多这样的例子,比如CCTV可以报道医疗,教育等领域的信息。晨报也可以报道。对于他们获取的新闻,他们不可能直接去一个领域类为大家报道新闻,那么现实中他们是怎么让大家了解新闻的呢?对于CCTV的报道我们再熟悉不过了,那就是每天7点的新闻,而新闻发言人就充当着门面角色(Facade),晨报的报纸充当着门面角色。下面2张图可以形象的说明这个道理。

门面模式(也叫外观模式,Facade)

1. 意图
为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
2. 动机
将一个系统划分成为若干个子系统有利于降低系统的复杂性。一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小。达到该目标的途径之一是就是引入一个外观(facade)对象,它为子系统中较一般的设施提供了一个单一而简单的界面。

3. 适用性

1)当你要为一个复杂子系统提供一个简单接口时。
子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。
Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过facade层。
2)客户程序与抽象类的实现部分之间存在着很大的依赖性。
引入facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
3)当你需要构建一个层次结构的子系统时
使用facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过facade进行通讯,从而简化了它们之间的依赖关系。

4. 结构

5. 参与者

• Facade ( Compiler )
— 知道哪些子系统类负责处理请求。
— 将客户的请求代理给适当的子系统对象。
• Subsystem classes ( Scanner、Parser、ProgramNode等)
— 实现子系统的功能。
— 处理由Facade对象指派的任务。
— 没有facade的任何相关信息;即没有指向facade的指针。
6. 协作

• 客户程序通过发送请求给Facade的方式与子系统通讯, Facade将这些消息转发给适当的子系统对象。尽管是子系统中的有关对象在做实际工作,但Facade模式本身也必须将它的接口转换成子系统的接口。
• 使用Facade的客户程序不需要直接访问子系统对象。
7. 效果

1) 它对客户屏蔽子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。
2) 它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。
3) 如果应用需要,它并不限制它们使用子系统类。因此你可以在系统易用性和通用性之间加以选择。
8. 实现

1) 降低客户-子系统之间的耦合度
2) 公共子系统类与私有子系统类

下面我们对于我们之前的商场收银系统进行我们希望的改进:

DAL层代码(目前是读配置文件,以后可以很容易的修改为访问数据库) 
using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Data; 
namespace 商场管理软件.DAL 
{ 
	public class CashAcceptType 
	{ 
		public DataSet GetCashAcceptType() 
		{ 
			//读配置文件到DataSet 
			DataSet ds = new DataSet(); 
			ds.ReadXml("CashAcceptType.xml"); 
			return ds; 
		} 
	} 
} 


这里后期我们完全可以用工厂模式来达到支持多种数据库。

BLL层主要代码(Facade类代码) 
namespace 商场管理软件.BLL 
{ 
	public class CashFacade 
	{ 
		const string ASSEMBLY_NAME = "商场管理软件.BLL"; 
		//得到现金收取类型列表,返回字符串数组 
		public string[] GetCashAcceptTypeList() 
		{ 
			CashAcceptType cat = new CashAcceptType(); 
			DataSet ds = cat.GetCashAcceptType(); 
			int rowCount = ds.Tables[0].DefaultView.Count; 
			string[] arrarResult = new string[rowCount]; 
			for (int i = 0; i < rowCount; i++) 
			{ 
				arrarResult[i] = 									(string)ds.Tables[0].DefaultView[i]["name"]; 
			} 
			return arrarResult; 
		} 
		/// <summary> 
		/// 用于根据商品活动的不同和原价格,计算此商品的实际收费 
		/// </summary> 
		/// <param name="selectValue">下拉列表选择的折价类型</param> 
		/// <param name="startTotal">原价</param> 
		/// <returns>实际价格</returns> 
		public double GetFactTotal(string selectValue, double startTotal) 
		{ 
			CashAcceptType cat = new CashAcceptType(); 
			DataSet ds = cat.GetCashAcceptType(); 
			CashContext cc = new CashContext(); 
			DataRow dr = ( (DataRow[])ds.Tables[0].Select("name='" + selectValue + "'") )[0]; 
			object[] args = null; 
			if (dr["para"].ToString() != "") 
			args = dr["para"].ToString().Split(','); 
			cc.setBehavior( 
			(CashSuper)Assembly.Load(ASSEMBLY_NAME).CreateInstance( 
			ASSEMBLY_NAME + "." + dr["class"].ToString(), 
			false, BindingFlags.Default, null, args, null, null ) ); 
			return cc.GetResult(startTotal); 
		} 
	} 
} 


UI层代码(可以很容易的转换为Web页面) 
double total = 0.0d;//用于总计 
CashFacade cf = new CashFacade(); 
private void Form1_Load(object sender, EventArgs e) 
{ 
	//读数据绑定下拉列表 
	cbxType.DataSource = cf.GetCashAcceptTypeList(); 
	cbxType.SelectedIndex = 0; 
} 
private void btnOk_Click(object sender, EventArgs e) 
{ 
	double totalPrices = 0d; 
	//传进下拉选择值和原价,计算实际收费结果 
	totalPrices = cf.GetFactTotal( 
	cbxType.SelectedItem.ToString(), 
	Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text) ); 
	total = total + totalPrices; 
	lbxList.Items.Add( 
		"单价:" + txtPrice.Text + 
		" 数量:" + txtNum.Text + " " + cbxType.SelectedItem + 
		" 合计:" + totalPrices.ToString()); 
	lblResult.Text = total.ToString(); 
} 

我们可以对比下最原始的代码和我们经过好几次重构后的现在的代码,两段表示层的代码同样的简单,那么孰优孰劣呢?


门面模式就给大家介绍到这里吧,大家看到这里,应该或多或少有些收获了,软件设计模式,其实很多都是在我们实际开发过程中遇到了问题,然后解决,然后总结出来的经验,所形成的模式。

现在我们再将系列一设计模式的定义拿出来看看,设计模式是指在软件开发中经过验证的用于解决在特定环境重复出现特定问题解决方案确实是这么回事。

分享到:
评论

相关推荐

    设计模式之门面模式(Facade模式)

    设计模式之门面模式(Facade模式),介绍门面模式,实际例子分析,代码讲解等

    设计模式C++学习之门面模式(Facade)

    设计模式C++学习之门面模式(Facade)

    C++设计模式课件14_Facade_门面模式.pdf

    C++设计模式课件14_Facade_门面模式.pdf

    设计模式之Facade

    eclipse工程文件 包含代码 有助理解 门面(Facade)模式 &lt;br&gt;外部与一个子系统的通信必须通过一个统一的门面(Facade)对象进行,这就是门面模式。 &lt;br&gt;医院的例子 &lt;br&gt;用一个例子进行说明,如果把医院...

    设计模式 之 “门面模式[Facade Pattern]”

    NULL 博文链接:https://lym6520.iteye.com/blog/707060

    C#设计模式.PDF

    完整的C#设计模式PDF版 C#设计模式(1) 4 一、 C# 面向对象程序设计复习 5 二、 设计模式举例 5 三、 先有鸡还是先有蛋? 7 四、 大瓶子套小瓶子还是小瓶子套大瓶子? 8 五、 .net本质 9 C#设计模式(2) 11 一、 ...

    facade门面模式

    java设计模式门面模式java设计模式门面模式

    08-Facade.rar

    Facade.rarFacade.rarFacade.rarFacade.rar门面设计模式

    源码:阎宏设计模式光盘

    com.javapatterns.javaio 专题:设计模式在Java I/O中的应用 com.javapatterns.keygen 专题:序列键生成器与单例及多例模式 com.javapatterns.liskov 里氏代换原则 com.javapatterns.lod 迪米特法则 ...

    Java设计模式

    Java设计模式 策略模式【STRATEGY PATTERN】 .................................................................................................. 4 第 2 章 代理模式【PROXY PATTERN】 ..........................

    php设计模式 Facade(外观模式)

    模式定义:外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观...

    软件开发中的23种设计模式

    23种模式(Pattern) 1、创建形模式: 1)、单用型:Singleton 2)、工厂方法型:Factory Method...3)、门面模式:Facade 4)、装饰模式:Decorator 3、行为型模式 1)、策略模式:Strategy 2)、观察者模式:Observer

    解析C#设计模式编程中外观模式Facade Pattern的应用

    主要介绍了C#设计模式编程中外观模式Facade Pattern的应用,外观模式中分为门面(Facade)和子系统(subsystem)两个角色来进行实现,需要的朋友可以参考下

    学习php设计模式 php实现门面模式(Facade)

    为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层次的接口,使得子系统更加容易使用【GOF95】 外部与子系统的通信是通过一个门面(Facade)对象进行。 二、门面模式结构图 三、门面模式中主要角色 ...

    23种设计模式的实现(Java 版),java设计模式

    Factory模式,Prototype模式,Builder 模式,Singleton模式,Facade模式,Proxy模式,Adapter模式,Composite模式,Decorator模式....

    C#设计模式大全

    C#设计模式(1) 一、 C# 面向对象程序设计复习 二、 设计模式举例 三、 先有鸡还是先有蛋? 四、 大瓶子套小瓶子还是小瓶子套大瓶子? 五、 .net本质 C#设计模式(2) 一、 "开放-封闭"原则(OCP) 二、 ...

    Java24种设计模式,Java24种设计模式,24种设计模式,学会了这24种设计模式,可以打遍天下无敌手,设计模式非常重要

    7、门面模式FACADE PATTERN 8、适配器模式ADAPTER PATTERN 9、模板方法模式TEMPLATE METHOD PATTERN 10、建造者模式BUILDER PATTERN 11、桥梁模式BRIDGE PATTERN 12、命令模式COMMAND PATTERN 13、装饰模式...

    JAVA设计模式.rar

    门面模式【FACADE PATTERN】  适配器模式【ADAPTER PATTERN】  模板方法模式【TEMPLATE METHOD PATTERN】  建造者模式【BUILDER PATTERN】 桥梁模式【BRIDGE PATTERN】  命令模式【COMMAND PATTERN...

    JAVA设计模式(门面模式)—视频

    什么是门面模式(Facade) 外部与一个子系统的通信必须通过一个统一的门面对象进行。这就是门面模式。 门面模式的结构 涉及两个角色: 门面角色:客户端可以调用这个角色的方法。此角色知道子系统的功能和责任。在...

    网络编程、常用设计模式

    详细的jsp网络编程、常用设计模式! 前言 3 第一部分:网络编程 4 一、了解URL 4 二、读取URL中的资源 4 1、URL构造方法: 5 2、读取资源 5 三、INETADDRESS类 5 四、SOCKET类 6 1、Socket套接字连接 6 2、Socket...

Global site tag (gtag.js) - Google Analytics