设计模式:外观(Facade)模式
一、前言
外观模式是一种非常简单的模式,简单到我们经常都会使用,比如对于类A和B,如果两者需要交互,经过一定的处理过程才能实现某一个具体的功能,那么我们可以将这个处理的过程定义为一个新的类,然后在这个类里面将类A和B的处理步骤整合在一起,对于外界我们只暴露新的类中的这个接口,这样代码的复用性就非常的好了,可以将这些代码作为组件去让其他程序去使用,这在我们的开发之中是非常常见的。甚至我们可以将抽象工厂模式中创建产品的接口当做外观模式的一种应用,这也是一种整合。对于模板方法,其实我们也是在父类之中面向抽象编程的,将一些关系整合起来,不过差别还是非常明显的,在外观模式中没有继承关系,是新建一个类来整合其它类之间复杂的相互依赖,调用等关系,因此外观模式比较直观。
二、代码
DataBase 类:
1 package zyr.dp.facade; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.IOException; 6 import java.util.Properties; 7 8 public class DataBase { 9 private DataBase(){ 10 11 } 12 public static Properties getProperties(String dbName){ 13 Properties pro=new Properties(); 14 15 try { 16 pro.load(new FileInputStream(dbName+".txt")); 17 } catch (FileNotFoundException e) { 18 e.printStackTrace(); 19 } catch (IOException e) { 20 e.printStackTrace(); 21 } 22 return pro; 23 } 24 25 }
HTMLWriter类:
1 package zyr.dp.facade; 2 3 import java.io.IOException; 4 import java.io.Writer; 5 6 public class HTMLWriter { 7 8 private Writer writer; 9 public HTMLWriter(Writer writer){ 10 this.writer=writer; 11 } 12 public void title(String theTitle){ 13 try { 14 writer.write("<html><head><title>"+theTitle+"</title></head><body> "); 15 writer.write("<h1>"+theTitle+"</h1> "); 16 } catch (IOException e) { 17 e.printStackTrace(); 18 } 19 } 20 public void paragraph(String msg){ 21 try { 22 writer.write("<p>"+msg+"</p> "); 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } 26 } 27 public void link(String href,String caption){ 28 paragraph("<a href=""+href+"" >"+caption+"</a>"); 29 } 30 public void mailTo(String mailAddr,String username) { 31 link("mailto:"+mailAddr,username); 32 } 33 public void close() { 34 try { 35 writer.write("</body></html> "); 36 writer.close(); 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } 40 } 41 }
PageMaker类:
1 package zyr.dp.facade; 2 3 import java.io.FileWriter; 4 import java.io.IOException; 5 import java.util.Properties; 6 7 public class PageMaker { 8 private PageMaker(){ 9 } 10 public static void makePage(String mailAddr,String filename) throws IOException{ 11 Properties pro=DataBase.getProperties("mailData"); 12 String username=pro.getProperty(mailAddr); 13 HTMLWriter html=new HTMLWriter(new FileWriter(filename)); 14 html.title("编程之美"); 15 html.paragraph("欢迎 "+username+" 来到我的程序空间!"); 16 html.paragraph("这里有你想要的一切~~"); 17 html.mailTo(mailAddr, username); 18 html.close(); 19 System.out.println("为"+username+"创建"+filename+"文件成功!"); 20 } 21 22 }
main类:
1 package zyr.dp.facade; 2 3 import java.io.IOException; 4 5 public class Main { 6 7 public static void main(String[] args) { 8 try { 9 PageMaker.makePage("2655100328@qq.com", "my_html.html"); 10 } catch (IOException e) { 11 e.printStackTrace(); 12 } 13 } 14 15 }
mailData存放的位置和内容:(注意如果使用相对地址,对于java程序来说src的上一级就是相对地址的起始地址,如果要放到src里面可以使用“./src/...”)。
运行结果:
虽然程序很简单,但是要注意的地方一点也不少,首先就是我们要将外观模式的接口对应的类(pageMaker)以及一些不用生成对象的工具类的构造函数设为私有,不让外部类去创建实例,其次,我们要注意properties读取文件的时候使用相对路径应该从哪个地方开始读写,另外当我们的程序变得复杂的时候,如果将这些类封装成一个模块,如何防止类外的对象访问我们的类呢,可以将除了facade类之外的类的属性设为默认的,这样就能很好的实现高内聚低耦合的设计思想了。这些类本来没关系,但是通过一个整合之后,产生了一定的关联,在实际开发中可能形成递归结构,那就是一个facade模式中使用了很多其他的facade模式,这样不断地实现下去,形成一个facade模式树,因此灵活使用设计模式至关重要。
三、总结
facade外观模式是一种非常常用的模式,特别是在组织一些复杂的相互调用的逻辑的时候,为外界提供统一的接口(API),可以看到在设计模式中,最常用的应该就是模板方法和facade模式了,很多时候很多需求需要我们认真的取舍,人无远虑必有近忧,同样的,只有为以后的可复用性、可扩展性来考虑,我们的代码才是好的代码。