装饰模式(别名:包装器)
动态地给对象添加一些额外的职责。就功能来说装饰模式相比生成子类更为灵活。
Decorator Pattern(Another Name: Wrapper)
Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
一 、 概述
装饰模式是动态地扩展一个对象的功能,而不需要改变原始类代码的一种成熟模式。在装饰模式中,“具体组件”类和“具体装饰”类是该模式中的最重要的两个角色。
假设系统中有一个Bird抽象类以及Bird类的一个子类:Sparrow。Sparrow类实现了Bird类的fly方法,使得Sparrow类创建的对象调用fly方法能连续飞行100米。现在用户需要两种鸟,必须分别能连续飞行150米和200米。
二、装饰模式模式的结构与使用
装饰模式的结构中包括四种角色:
抽象组件(Component)
具体组件(ConcreteComponent)
装饰(Decorator)
具体装饰(ConcreteDecotator)
值得注意的是具体组件和抽象的装饰都泛化了component,后者之所以泛化主要是有相同的类型,并且装饰持有被装饰着【组件的引用】,两者是依赖关系
具体的装饰者还能附加新的方法,在原有的基础上进行扩充。
1.抽象组件 : Bird.java
public abstract class Bird{
public abstract int fly();
}
2.具体组件 : Sparrow.java
public class Sparrow extends Bird{
public final int DISTANCE=100;
public int fly(){
return DISTANCE;
}
}
3.装饰 (Decorator): Decorator.java
public abstract class Decorator extends Bird{
protected Bird bird;
public Decorator(){
}
public Decorator(Bird bird){
this.bird=bird;
}
}
4.具体装饰(ConcreteDecotator): SparrowDecorator.java
public class SparrowDecorator extends Decorator{
public final int DISTANCE=50; //eleFly方法能飞50米
SparrowDecorator(Bird bird){
super(bird);
}
public int fly(){
int distance=0;
distance=bird.fly()+eleFly();
return distance;
}
private int eleFly(){ //装饰者新添加的方法
return DISTANCE;
}
}
5.应用 Application.java
public class Application{
public void needBird(Bird bird){
int flyDistance=bird.fly();
System.out.println("这只鸟能飞行"+flyDistance +"米");
}
public static void main(String args[]){
Application client=new Application ();
Bird sparrow=new Sparrow();
Bird sparrowDecorator1=
new SparrowDecorator(sparrow);
Bird sparrowDecorator2=
new SparrowDecorator(sparrowDecorator1);
client.needBird(sparrowDecorator1);
client.needBird(sparrowDecorator2);
}
}
也许这里例子并不那么形象,我们思考一下,当我们喝咖啡的时候,咖啡作为一个组件,具体组件,有各种特色的咖啡,装饰者就好比各种调料,加奶,加糖。。
如果使用传统的继承方式实现,就是在原有的具体组件上添加成员吧,代码都是写死的,我们利用装饰着模式可以动态的扩展,动态的再装饰,最关键的是对外仍然呈现原有的类
型还可以在原有的继承的行为进行进一步扩充。【一点点套】 缺点是子类太多
三、装饰模式的优点
被装饰者和装饰者是松耦合关系。由于装饰(Decorator)仅仅依赖于抽象组件(Component)【依赖倒置原则】,因此具体装饰只知道它要装饰的对象是抽
象组件的某一个子类的实例,但不需要知道是哪一个具体子类。
装饰模式满足“开-闭原则”。不必修改具体组件,就可以增加新的针对该具体组件的具体装饰。可以使用多个具体装饰来装饰具体组件的实例。
四.常见的应用
FileInputStream.java
import java.nio.channels.FileChannel;
import sun.nio.ch.FileChannelImpl;
public
class FileInputStream extends InputStream
{
private FileDescriptor fd;
private FileChannel channel = null;
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
java.lang.SecurityManager#checkRead(java.lang.String)
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
fd = new FileDescriptor();
open(name);
}
public FileInputStream(FileDescriptor fdObj) {
SecurityManager security = System.getSecurityManager();
if (fdObj == null) {
throw new NullPointerException();
}
if (security != null) {
security.checkRead(fdObj);
}
fd = fdObj;
}
private native void open(String name) throws FileNotFoundException;
public native int read() throws IOException;
private native int readBytes(byte b[], int off, int len) throws IOException;//非Java实现
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len);
}
public native long skip(long n) throws IOException;
public native int available() throws IOException;
public void close() throws IOException {
if (channel != null)
channel.close();
close0();
}
public final FileDescriptor getFD() throws IOException {
if (fd != null) return fd;
throw new IOException();
}
public FileChannel getChannel() {
synchronized (this) {
if (channel == null)
channel = FileChannelImpl.open(fd, true, false, this);
return channel;
}
}
private static native void initIDs();
private native void close0() throws IOException;
static {
initIDs();
}
protected void finalize() throws IOException {
if (fd != null) {
if (fd != fd.in) {
close();
}
}
}
}
FilterInputStream.java
public
class FilterInputStream extends InputStream {
protected volatile InputStream in;//持有引用对象
protected FilterInputStream(InputStream in) {
this.in = in;
}
public int read() throws IOException {
return in.read();
}
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
return in.read(b, off, len);
}
public long skip(long n) throws IOException {
return in.skip(n);
}
public int available() throws IOException {
return in.available();
}
public void close() throws IOException {
in.close();
}
public synchronized void mark(int readlimit) {
in.mark(readlimit);
}
public synchronized void reset() throws IOException {
in.reset();
}
public boolean markSupported() {
return in.markSupported();
}
}
通过这个类再派生了BufferedReader等类