Facade模式——简单窗口
当调用大型程序进行处理时,我们需要格外注意那些数量庞大的类之间错综复杂的关系。不过有一种更简单的做法,就是为这个大型程序提供一个“窗口”。这样,我们就不必单独地关注每个类了,只需简单地对“窗口”提出请求即可。
这个“窗口”就是Facade模式。使用Facade模式可以为相互关联在一起的错综复杂的类整理出高层接口(API)。其中的Facade角色可以让系统对外只有一个简单的接口(API)。而且,Facade角色还会考虑到系统内部各个类之间的责任关系和依赖关系,按照正确的顺序调用各个类。
下面的示例程序将要编写简单的Web页面。
- 类的一览表
包 | 名字 | 说明 |
---|---|---|
pagemaker | Database | 从邮件地址中获取用户名的类 |
pagemaker | HtmlWriter | 编写HTML文件的类 |
pagemaker | PageMaker | 根据邮件地址编写该用户的Web页面 |
default | Main | 测试程序行为的类 |
- Database类
package pagemaker;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
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) {
System.out.println("Warning: " + filename + " is not found.");
}
return prop;
}
}
- HtmlWriter类
package pagemaker;
import java.io.IOException;
import java.io.Writer;
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>");
}
public void mailto(String mailaddr,String username) throws IOException {
link("mailto:" + mailaddr, username);
}
public void close() throws IOException {
writer.write("</body>");
writer.write("</html>\n");
writer.close();
}
}
- PageMaker类
package pagemaker;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class PageMaker {
private PageMaker() {}
public static void makeWelcomePage(String mailaddr, String filename) {
try {
Properties mailprop = Database.getProperties("D:\\i编程" +
"\\IntelliJ IDEA Community Edition 2017.3.4\\workspace" +
"\\Program\\src\\DesignPatterns\\FacadePattern\\maildata");
String username = mailprop.getProperty(mailaddr);
HtmlWriter writer = new HtmlWriter(new FileWriter(filename));
writer.title("Welcome to " + username + "'s page!");
writer.paragraph("欢迎来到" + username + "的主页");
writer.paragraph("期待你的邮件!");
writer.mailto(mailaddr, username);
writer.close();
System.out.println(filename + " is created for " + mailaddr + " (" + username + ")");
} catch (IOException e) {
e.printStackTrace();
}
}
}
- Main类
import pagemaker.PageMaker;
public class Main {
public static void main(String[] args) {
PageMaker.makeWelcomePage("hyuki@hyuki.com", "welcome.html");
}
}
- maildata.txt
hyuki@hyuki.com=Hiroshi Yuki
hanako@hyuki.com=Hanako Sato
tomura@hyuki.com=Tomura
mamoru@hyuki.com=Mamoru Takahashi
示例输出如下:
<html><head><title>Welcome to Hiroshi Yuki's page!</title></head><body>
<h1>Welcome to Hiroshi Yuki's page!</h1>
<p>欢迎来到Hiroshi Yuki的主页</p>
<p>期待你的邮件!</p>
<p><a href="mailto:hyuki@hyuki.com">Hiroshi Yuki</a></p>
</body></html>
##Facade模式中的角色
- Facade(窗口)
Facade角色是代表构成系统的许多其他角色的“简单窗口”。Facade角色向系统外部提供高层接口(API)。在示例程序中,由PageMaker类扮演此角色。
- 构成系统的许多其他角色
这些角色各自完成自己的工作,它们并不知道Facade角色。Facade角色调用其他角色进行工作,但是其他角色不会调用Facade角色。在示例程序中,由Database类和HtmlWriter类扮演此角色。
- Client(请求者)
Client角色负责调用Facade角色。在示例程序中,由Main类扮演此角色。
##Facade模式的思路
Facade模式可以让复杂的东西看起来简单,隐藏了后台工作的这些类之间的关系和它们的使用方法,重点是接口变少了,调用一个接口可以实现很多方法和类的递归调用,使功能的实现更加简单。