1. 概述
隨著業(yè)務(wù)復(fù)雜度的增加,系統(tǒng)程序中類的調(diào)用關(guān)系也會(huì)越來(lái)越復(fù)雜侦鹏。這在日常工作中非常常見。如果放任不管臀叙,讓大量的類散落在項(xiàng)目中,會(huì)對(duì)將來(lái)的拓展和維護(hù)造成大量麻煩价卤。
為了解決這個(gè)問(wèn)題劝萤,我們提出了 facade 模式。Facade 即窗口慎璧,這個(gè)模式的核心要義就是通過(guò)一個(gè)窗口角色床嫌,隱藏復(fù)雜的類調(diào)用關(guān)系,只暴露簡(jiǎn)潔的接口給 client胸私。這樣當(dāng) client 需要完成一段邏輯業(yè)務(wù)時(shí)厌处,不需要關(guān)系業(yè)務(wù)內(nèi)部的各個(gè)類是如何相互調(diào)用的。
用實(shí)際的例子類比岁疼,就像去飯店吃飯阔涉,客人只需要點(diǎn)菜下單,不需要考慮每一道菜用什么材料捷绒,找什么廚師來(lái)做瑰排。菜單就是面向客戶的窗口,客戶只需調(diào)用點(diǎn)菜的 API暖侨,就可以吃到美味的飯菜椭住,而不需要考慮具體的制作過(guò)程。
2. 模式類圖
3. 模式角色
Facade(窗口)
Facade 角色即窗口角色字逗,向系統(tǒng)外部提供高層接口京郑。
Client(請(qǐng)求者)
Client 角色調(diào)用 Facade 角色定義的接口。(當(dāng)然葫掉,嚴(yán)格來(lái)說(shuō) Client 并不是 Facade 模式中的角色)
構(gòu)成系統(tǒng)的其他角色們
組成系統(tǒng)的各個(gè)功能角色些举,它們并不關(guān)心 Facade 角色的存在,只執(zhí)行自己的功能挖息。Facade 角色負(fù)責(zé)調(diào)用它們組成完整的業(yè)務(wù)功能金拒。
4. 代碼示例
我們用一個(gè)打印 html 頁(yè)面的場(chǎng)景舉例。系統(tǒng)中包含從數(shù)據(jù)庫(kù)讀取數(shù)據(jù)的類套腹,組裝 html 頁(yè)面內(nèi)容的類绪抛。它們通過(guò)一個(gè)頁(yè)面生成類整合。最終的 main 方法不用關(guān)心數(shù)據(jù)如何讀取电禀,html結(jié)構(gòu)如何組裝幢码,只需要調(diào)用“生成頁(yè)面”即可。
首先定義一個(gè)數(shù)據(jù)讀取類尖飞。
Database.java
public class Database {
private Database() {
}
public static Properties getProperties(String dbName) {
String fileName = dbName + ".txt";
Properties prop = new Properties();
try {
prop.load(new FileInputStream(fileName));
} catch (IOException e) {
e.printStackTrace();
System.out.println("ERROR: " + fileName + " not found!");
}
return prop;
}
}
同時(shí)定義數(shù)據(jù)源症副。這里的數(shù)據(jù)源只是一個(gè) properties 文件店雅。
aaron@google.com=aaron
tom@google.com=tom
lucy@google.com=lucy
然后定義一個(gè) Html 頁(yè)面構(gòu)造類。
HtmlWriter.java
public class HtmlWriter {
private Writer writer;
public HtmlWriter(Writer writer) {
this.writer = writer;
}
public void title(String title) throws IOException {
writer.write("<html>");
writer.write("<head>");
writer.write("<title>" + title + "</title>");
writer.write("</head>");
writer.write("<body>\n");
writer.write("<h1>" + title + "</h1>\n");
}
public void paragraph(String msg) throws IOException {
writer.write("<p>" + msg + "</P>\n");
}
public void link(String href, String caption) throws IOException {
paragraph("<a href=\"" + href + "\">" + caption + "</a>\n");
}
public void mailto(String mailName, String userName) throws IOException {
link("mailto:" + mailName, userName);
}
public void close() throws IOException {
writer.write("</body>");
writer.write("</html>\n");
writer.close();
}
}
接下來(lái)就是定義 facade 角色贞铣。我們創(chuàng)建一個(gè) PageMarker 類闹啦。負(fù)責(zé)協(xié)調(diào)調(diào)用 Database 和 HtmlWriter,整合功能辕坝。
PageMarker.java
public class PageMaker {
private PageMaker() {
}
public static void makeWelcomePage(String mailAddr, String fileName) {
try {
Properties mailProp = Database.getProperties("mailData");
String userName = mailProp.getProperty(mailAddr);
HtmlWriter writer = new HtmlWriter(new FileWriter(fileName));
writer.title("Welcome to " + userName + "'s page!");
writer.paragraph("歡迎來(lái)到" + userName + "的主頁(yè)窍奋!");
writer.paragraph("等待你的郵件哦");
writer.mailto(mailAddr, userName);
writer.close();
System.out.println(fileName + " is created for " + mailAddr + " (" + userName + ")");
} catch (IOException e) {
e.printStackTrace();
}
}
}
最后用 main 方法作為 client 調(diào)用 facade 角色給出的接口。
Main.java
public class Main {
public static void main(String[] args) {
PageMaker.makeWelcomePage("aaron@google.com", "home.html");
}
}
結(jié)果:
home.html is created for aaron@google.com (aaron)
<html><head><title>Welcome to aaron's page!</title></head><body>
<h1>Welcome to aaron's page!</h1>
<p>歡迎來(lái)到aaron的主頁(yè)酱畅!</P>
<p>等待你的郵件哦</P>
<p><a href="mailto:aaron@google.com">aaron</a>
</P>
</body></html>