1.概述
外观模式(Façade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层的接口,这个接口使得这个子系统更加容易使用。通过这个接口,其他系统可以方便的调用子系统中的功能,而忽略子系统内部发生的变化。
外观模式(Façade)是经常使用的模式之一,并且可以应用在任何层次和粒度的应用中,小到API的封装,大到封装整个系统。例如在使用ADO.NET时,为了执行SQL,需要使用Connection,Command和DataAdapter等,这样显然比较的麻烦,因此我们可以将整个数据库访问封装到一个类中,该类封装了访问数据库的过程,这个类就是一个外观模式。
下面我们看外观模式的结构:
结构图说明:
外观类(Facade):客户端可以调用这个类的方法。此类知晓相关的(一个或者多个)子系统的功能和责任。在正常情况下,本类会将所有从客户端发来的请求委派到相应的子系统去。
子系统(subsystem):可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。每一个子系统都可以被客户端直接调用,或者被外观类调用。子系统并不知道门面的存在,对于子系统而言,外观类仅仅是另外一个客户端而已。
基本代码:(来自大话设计模式)
四个子系统类:
public class SubSystemOne
{
public void MethodOne()
{
Console.WriteLine(" 子系统方法一");
}
}
public class SubSystemTwo
{
public void MethodTwo()
{
Console.WriteLine(" 子系统方法二");
}
}
public class SubSystemThree
{
public void MethodThree()
{
Console.WriteLine(" 子系统方法三");
}
}
public class SubSystemFour
{
public void MethodFour()
{
Console.WriteLine(" 子系统方法四");
}
}
外观类:
public class Facade
{
SubSystemOne one;
SubSystemTwo two;
SubSystemThree three;
SubSystemFour four;
public Facade()
{
one = new SubSystemOne();
two = new SubSystemTwo();
three = new SubSystemThree();
four = new SubSystemFour();
}
public void MethodA()
{
Console.WriteLine("\n方法组A() ---- ");
one.MethodOne();
two.MethodTwo();
four.MethodFour();
}
public void MethodB()
{
Console.WriteLine("\n方法组B() ---- ");
two.MethodTwo();
three.MethodThree();
}
}
客户端调用(由于Facade的作用,客户端可以根本不知道四个子系统类的存在):
public class Program
{
static void Main(string[] args)
{
Facade facade = new Facade();
facade.MethodA();
facade.MethodB();
Console.Read();
}
}
2.实例
数据库访问外观模式:
在使用ADO.NET访问数据库时,我们通常需要编写下面的访问数据库的语句来访问数据库:
SqlConnection myConn = new SqlConnection();
myConn.ConnectionString = "Database=xxx;Server=local;User Id=sa;Password=123456;";
myConn.Open();
DataTable dt = new DataTable();
SqlCommand cmd = new SqlCommand(strSQL);
SqlDataAdapter da = new SqlDataAdapter(cmd);
cmd.Connection = myConn;
da.Fill(dt);
myConn.Close();
如上面的代码所示,为了执行一个SQL,需要使用Connection、Command和DataAdapter,这样显然比较麻烦,因此,我们可以利用外观模式,将数据库访问封装到一个类中,该类分装了访问数据库的过程。下面是给出一个通用的封装的数据访问层,代码如下:
using System;
using System.Data;
using System.Collections;
namespace DAL
{
/// <summary>
/// DALResult
/// Copyright peida 2008-7-15
/// </summary>
public class DALResult
{
public bool IsSucceed; //存储过程是否执行成功
public string errorMessage; //访问数据库失败
public int rowsCount; //结果集行数.
public object theFirst; //第一行第一列
public Hashtable OutputValues; //存储过程output值,放在(HashTable)表OutputValues里.
public DataTable datatable; //存储过程返回的结果集,放在(DataTable)表datatable里.
public DataSet dataSet; //存储过程返回的结果集,放在DataSet表中
public DALResult()
{
IsSucceed = false;
rowsCount = 0;
errorMessage = "";
theFirst = null;
OutputValues = new Hashtable();
datatable=new DataTable();
dataSet=new DataSet();
}
}
}
SQL语句的分装:
using System;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
namespace DAL
{
/// <summary>
/// SQL_Base 调用SQL语句
/// Copyright peida 2008-7-15
/// </summary>
public class SQL_Base : IDisposable
{
private string strconn = "";
public SQL_Base() : this("")
{
strconn = ConfigurationSettings.AppSettings["DBpath"];
}
//重载
public SQL_Base(string sql_name)
{
strconn = ConfigurationSettings.AppSettings[sql_name];
}
//私有成员变量
private string sql_name;
private SqlConnection myConnection;
private SqlCommand myCommand;
//公共属性
public string SQLName
{
get
{
return this.sql_name;
}
set
{
this.sql_name = value;
}
}
/// <summary>
/// 执行SQL语句,返回数据集:DataTable或DataSet
/// </summary>
/// <returns>返回DALResult</returns>
public DALResult ExecuteSqlData()
{
DALResult result = new DALResult();
myConnection = new SqlConnection(strconn);
myCommand = new SqlCommand(this.sql_name, myConnection);
myCommand.CommandType = CommandType.Text;
SqlDataAdapter myAdapter = new SqlDataAdapter(myCommand);
myConnection.Open();
using(SqlTransaction trans = myConnection.BeginTransaction())
{
try
{
if(trans!=null)
{
myCommand.Transaction = trans;
}
//填充数据,将结果填充到DALResult集中
myAdapter.Fill(result.dataSet);
if(result.dataSet.Tables.Count>0)
{
result.datatable=result.dataSet.Tables[0].Copy();
if(result.dataSet.Tables[0].Rows.Count>0)
{
result.rowsCount = result.dataSet.Tables[0].Rows.Count;
}
}
result.IsSucceed = true;
//提交事物
trans.Commit();
}
catch(Exception e)
{
result.errorMessage = e.Message;
}
//如果捕捉了异常,但仍会执行包括在 finally 块中的输出语句
finally
{
myAdapter.Dispose();
myCommand.Dispose();
myConnection.Close();
myConnection.Dispose();
}
}
return result;
}
/// <summary>
/// 获取第一行第一列数据
/// </summary>
/// <returns>返回DALResult</returns>
public DALResult ExecuteSqlScalar()
{
DALResult result = new DALResult();
myConnection = new SqlConnection(strconn);
myCommand = new SqlCommand(this.sql_name, myConnection);
myCommand.CommandType = CommandType.Text;
myConnection.Open();
using(SqlTransaction trans = myConnection.BeginTransaction())
{
try
{
if(trans!=null)
{
myCommand.Transaction = trans;
}
object scalarresult = myCommand.ExecuteScalar();
if(Object.Equals(scalarresult,null))
{
result.errorMessage = "没有取到数据";
}
else
{
result.theFirst = scalarresult;
//取到数据
result.rowsCount=1;
}
result.IsSucceed = true;
//提交事物
trans.Commit();
}
catch(Exception e)
{
result.errorMessage = e.Message;
}
finally
{
myCommand.Dispose();
myConnection.Close();
myConnection.Dispose();
}
}
return result;
}
/// <summary>