1、装饰器模式(Decorator Pattern)
装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。它主要的作用是给原始类添加增强功能。这也是判断是否该用装饰器模式的一个重要的依据。除此之外,装饰器模式还有一个特点,那就是可以对原始类嵌套使用多个装饰器。为了满足这个应用场景,在设计的时候,装饰器类需要跟原始类继承相同的抽象类或者接口。
1.1、实例说明
现有一套图形界面显示构件库,在使用该库构建某图形界面时,用户要求为界面定制一些特效显示效果,如带滚动条的窗体或透明窗体等。
1.2、实例类图

1.3、实例代码
public abstract class Window {
protected abstract void display();
}
public class SimpleWindow extends Window {
@Override
protected void display() {
System.out.println("显示简单窗体");
}
}
public class WindowDecorator extends Window {
Window window;
WindowDecorator(Window window){
this.window = window;
}
@Override
protected void display() {
window.display();
}
}
public class ScrollbarDecorator extends WindowDecorator {
ScrollbarDecorator(Window window) {
super(window);
}
@Override
protected void display() {
super.display();
this.setScrollbar();
}
public void setScrollbar(){
System.out.println("装饰器增强滚动条功能。。。。");
}
}
public class TransparentDecorator extends WindowDecorator {
TransparentDecorator(Window window) {
super(window);
}
@Override
protected void display() {
super.display();
this.setTransparent();
}
public void setTransparent(){
System.out.println("装饰器增强透明窗体功能。。。。");
}
}
public class Client {
public static void main(String[] args) {
Window simpleWindow = new SimpleWindow();
Window scrollbarWindow = new ScrollbarDecorator(simpleWindow);
Window transparentWindow = new TransparentDecorator(scrollbarWindow);
transparentWindow.display();
}
}
1.4、装饰器模式在Java IO类库中的使用
在Java IO类库中,经常使用类似下面的代码:
InputStream in = new FileInputStream("C:\\upload_file\\IOTest.txt");
InputStream bin = new BufferedInputStream(in);
DataInputStream din = new DataInputStream(bin);
int data = din.readInt();
现在简单分析下装饰器模式在上面代码中的应用
类图:

抽取InputStream、BufferedInputStream和FileInputStream部分源码如下:
public abstract class InputStream implements Closeable {
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
}
public class FileInputStream extends InputStream{
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len);
}
private native int readBytes(byte b[], int off, int len) throws IOException;
}
public class FilterInputStream extends InputStream {
/**
* The input stream to be filtered.
*/
protected volatile InputStream in;
protected FilterInputStream(InputStream in) {
this.in = in;
}
public int read(byte b[], int off, int len) throws IOException {
return in.read(b, off, len);
}
}
public class BufferedInputStream extends FilterInputStream {
private static int DEFAULT_BUFFER_SIZE = 8192;
public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
public BufferedInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
public synchronized int read(byte b[], int off, int len) throws IOException{
//省略其他关于缓存功能的代码
in.read(buffer, pos, buffer.length - pos);
//省略其他关于缓存功能的代码
}
}
public class DataInputStream extends FilterInputStream implements DataInput {
public DataInputStream(InputStream in) {
super(in);
}
public final int readInt() throws IOException {
int ch1 = in.read();
int ch2 = in.read();
int ch3 = in.read();
int ch4 = in.read();
//在in.read()基础上,添加读取int功能
if ((ch1 | ch2 | ch3 | ch4) < 0)
throw new EOFException();
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
}
}
2、外观模式(Facade Pattern)
为了保证接口的可复用性(或者叫通用性),我们需要将接口尽量设计得细粒度一点,职责单一一点。但是,如果接口的粒度过小,在接口的使用者开发一个业务功能时,就会导致需要调用 n 多细粒度的接口才能完成。
相反,如果接口粒度设计得太大,一个接口返回 n 多数据,要做 n 多事情,就会导致接口不够通用、可复用性不好。接口不可复用,那针对不同的调用者的业务需求,我们就需要开发不同的接口来满足,这就会导致系统的接口无限膨胀。
外观模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。
2.1、实例说明
需要一个文件加密模块,加密流程包括三个操作,分别是读取源文件、加密、保存加密之后的文件。读取文件和保存文件使用流来实现,这三个操作相对独立,其业务代码封装在三个不同的类中。现在需要提供一个统一的加密外观类,用户可以直接使用该加密外观类完成文件的读取、加密、和保存三个操作,而不需要与每一个类进行交互。
2.2、实例类图

2.3、实例代码
public class FileReader {
public String read(String srcFile){
//省略读文件代码
return "";
}
}
public class FileWriter {
public void write(String txt,String destFile){
//省略写文件代码
}
}
public class CipherMachine {
public String encrypt(String txt){
//省略加密代码
return "";
}
}
public class EncryptFacade {
FileReader reader;
FileWriter writer;
CipherMachine cipherMachine;
EncryptFacade(){
this.reader = new FileReader();
this.writer = new FileWriter();
this.cipherMachine = new CipherMachine();
}
public void fileEncrypt(String srcFile,String destFile){
String txt = reader.read(srcFile);
String txtEncrypt = cipherMachine.encrypt(txt);
writer.write(txtEncrypt,destFile);
}
}
public class Client {
public static void main(String[] args) {
EncryptFacade ef = new EncryptFacade();
ef.fileEncrypt("C:\\upload_file\\IOTest.txt","C:\\upload_file\\IOTest.txt");
}
}
适配器模式和外观模式的共同点是,将不好用的接口适配成好用的接口。它们的区别:
适配器是做接口转换,将不同的接口转化为统一的接口,解决的是原接口和目标接口不匹配的问题。
外观模式做接口整合,将不同的接口整合为一个接口,解决的是多接口调用带来的问题。
网友评论