軟體的發展,Client程式經常會與複雜系統的內部子系統之間產生耦合,而導致客戶程式隨著子系統變化。
替子系統裡的許多介面定義一套統一的介面,讓子系統更方便使用。所以它的目的是簡化客戶程式與子系統之間的交互介面,將複雜系統的內部子系統與客戶程式之間的依賴解耦。
程式結構適用:
- 為一個複雜子系統提供一個簡單介面。
- 提高子系統的獨立性。
- 在層次化結構中,可以使用Facade Pattern定義系統中每一層的入口。
以借貸的方式來序述Facade的程式結構:
建構一個介面
public class Mortgage
{
private Bank bank = new Bank();
private Loan loan = new Loan();
private Credit credit = new Credit();
public bool IsEligible(Customer cust, int amount)
{
Console.WriteLine("{0} applies for {1:C}
loan\n", cust.Name,
amount);
bool eligible = true;
if (!bank.HasSufficientSavings(cust, amount))
{
eligible = false;
} else if
(!loan.HasNoBadLoans(cust))
{
eligible = false;
} else if
(!credit.HasGoodCredit(cust))
{
eligible = false;
}
return eligible;
}
}
顧客類和子系統類別的實現
public class Bank
{
public bool HasSufficientSavings(Customer c, int amount)
{
Console.WriteLine("確認銀行戶名: " + c.Name);
return true;
}
}
信用證子系統類別
public class Credit
{
public bool HasGoodCredit(Customer c)
{
Console.WriteLine("確認信用戶名: " + c.Name);
return true;
}
}
建立貸款的子系統
public class Loan
{
public bool HasNoBadLoans(Customer c)
{
Console.WriteLine("Check loans for " + c.Name);
return true;
}
}
顧客類別
public class Customer
{
private string name;
public Customer(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
}
}
實現模式
客戶程式類
public class MainApp
{
public static void Main()
{
//外觀
Mortgage mortgage = new Mortgage();
Customer customer = new Customer("Ann McKinsey");
bool eligable = mortgage.IsEligible(customer, 125000);
Console.WriteLine("\n" + customer.Name + " has been " + (eligable ? "Approved" : "Rejected"));
Console.ReadLine();
}
}
Client程式只依賴Mortgage,讓Mortgage遮罩了子系統之間的複雜的操作,達到內部子系統與Client程式之間的依賴。
Façade Pattern與.Net的實現,分為四個邏輯層,UI、Business Facade,Business Rule,Data Access。
Business Facade運用在.NET的職責:
UI將Request發送給Business Facade讓對請求進行初步的處理,判斷是否需要調用Business Rule,還是直接調用Data Access獲取資料。最後由Data Access訪問Database並按照來時的步驟返回結果到UI,來看具體的代碼實現。
UI調用業務外觀層,業務外觀層直接調用了資料訪問層,Data Access確認了先決的條件,取得了資料。在添加訂單時,UI調用Business Facade,Business Facade調用Business Role,Business Role進行複雜的邏輯處理後,再調用Data Access。
Facade模式不僅簡化了整個元件系統的介面,對於元件內部與外部客戶程式達到了一種解耦的效果,內部子系統不會影響到Facade介面的變化。Facade更注重從架構的層次去看整個系統,而不是單個類的層次。
-雲遊山水為知已逍遙一生而忘齡- 電腦神手
Business Facade運用在.NET的職責:
- 從UI接收用戶輸入,請求需要對資料進行唯讀訪問,使用Data Access
- 將請求傳遞到Business Rule
- 將回應從Business Rule返回到UI,使其調用之間維護臨時狀態
UI將Request發送給Business Facade讓對請求進行初步的處理,判斷是否需要調用Business Rule,還是直接調用Data Access獲取資料。最後由Data Access訪問Database並按照來時的步驟返回結果到UI,來看具體的代碼實現。
productSystem = new ProductSystem();
categorySet = productSystem.GetCategories(categoryID);
public CategoryData GetCategories(int categoryId)
{
ApplicationAssert.CheckCondition(categoryId >= 0, "Invalid Category Id", ApplicationAssert.LineNumber);
using (Categories accessCategories = new Categories())
{
return accessCategories.GetCategories(categoryId);
}
}
public void AddOrder()
{
ApplicationAssert.CheckCondition(cartOrderData != null, "Order requires data", ApplicationAssert.LineNumber);
ApplicationLog.WriteTrace("Duwamish7.Web.Cart.AddOrder:\r\nCustomerId: " +
cartOrderData.Tables[OrderData.CUSTOMER_TABLE].Rows[0][OrderData.PKID_FIELD].ToString());
cartOrderData = (new
OrderSystem()).AddOrder(cartOrderData);
}
public OrderData AddOrder(OrderData order)
{
ApplicationAssert.CheckCondition(order != null, "Order is required", ApplicationAssert.LineNumber);
(new
BusinessRules.Order()).InsertOrder(order);
return order;
}
public bool
InsertOrder(OrderData order)
{
bool isValid = true;
DataRow summaryRow =
order.Tables[OrderData.ORDER_SUMMARY_TABLE].Rows[0];
summaryRow.ClearErrors();
if (CalculateShipping(order) !=
(Decimal)(summaryRow[OrderData.SHIPPING_HANDLING_FIELD]))
{
summaryRow.SetColumnError(OrderData.SHIPPING_HANDLING_FIELD,
OrderData.INVALID_FIELD);
isValid = false;
}
if (CalculateTax(order) !=
(Decimal)(summaryRow[OrderData.TAX_FIELD]))
{
summaryRow.SetColumnError(OrderData.TAX_FIELD,
OrderData.INVALID_FIELD);
isValid = false;
}
isValid &= IsValidField(order, OrderData.SHIPPING_ADDRESS_TABLE,
OrderData.SHIP_TO_NAME_FIELD, 40);
DataRow paymentRow = order.Tables[OrderData.PAYMENT_TABLE].Rows[0];
paymentRow.ClearErrors();
isValid &= IsValidField(paymentRow,
OrderData.CREDIT_CARD_TYPE_FIELD, 40);
isValid &= IsValidField(paymentRow,
OrderData.CREDIT_CARD_NUMBER_FIELD, 32);
isValid &= IsValidField(paymentRow, OrderData.EXPIRATION_DATE_FIELD,
30);
isValid &= IsValidField(paymentRow, OrderData.NAME_ON_CARD_FIELD,
40);
isValid &= IsValidField(paymentRow, OrderData.BILLING_ADDRESS_FIELD,
255);
DataRowCollection itemRows =
order.Tables[OrderData.ORDER_ITEMS_TABLE].Rows;
Decimal subTotal = 0;
foreach (DataRow itemRow in itemRows)
{
itemRow.ClearErrors();
subTotal +=
(Decimal)(itemRow[OrderData.EXTENDED_FIELD]);
if ((Decimal)(itemRow[OrderData.PRICE_FIELD]) <= 0)
{
itemRow.SetColumnError(OrderData.PRICE_FIELD, OrderData.INVALID_FIELD);
isValid = false;
}
if ((short)(itemRow[OrderData.QUANTITY_FIELD])
<= 0)
{
itemRow.SetColumnError(OrderData.QUANTITY_FIELD,
OrderData.INVALID_FIELD);
isValid = false;
}
}
if (subTotal !=
(Decimal)(summaryRow[OrderData.SUB_TOTAL_FIELD]))
{
summaryRow.SetColumnError(OrderData.SUB_TOTAL_FIELD,
OrderData.INVALID_FIELD);
isValid = false;
}
if (isValid)
{
using (DataAccess.Orders ordersDataAccess = new DataAccess.Orders())
{
return (ordersDataAccess.InsertOrderDetail(order))
> 0;
}
}
else
return false;
}
UI調用業務外觀層,業務外觀層直接調用了資料訪問層,Data Access確認了先決的條件,取得了資料。在添加訂單時,UI調用Business Facade,Business Facade調用Business Role,Business Role進行複雜的邏輯處理後,再調用Data Access。
Facade模式不僅簡化了整個元件系統的介面,對於元件內部與外部客戶程式達到了一種解耦的效果,內部子系統不會影響到Facade介面的變化。Facade更注重從架構的層次去看整個系統,而不是單個類的層次。
-雲遊山水為知已逍遙一生而忘齡- 電腦神手
沒有留言:
張貼留言