单例
参考:http://blog.csdn.net/hust_is_lcd/article/details/7884320
1.认识装饰器模式
    装饰模式能够实现动态的为对象添加功能,是从一个对象外部来给对象添加功能。通常给对象添加功能,要么直接修改对象添加相应的功能,要么派生对应的子类来扩展,抑或是使用对象组合的方式。显然,直接修改对应的类这种方式并不可取。在面向对象的设计中,而我们也应该尽量使用对象组合,而不是对象继承来扩展和复用功能。装饰器模式就是基于对象组合的方式,可以很灵活的给对象添加所需要的功能。装饰器模式的本质就是动态组合。动态是手段,组合才是目的。总之,装饰模式是通过把复杂的功能简单化,分散化,然后再运行期间,根据需要来动态组合的这样一个模式。

         定义:装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

                 (1)不改变原类文件。

               (2)不使用继承。

                 (3)动态扩展。

2.模式结构和说明

    装饰模式的结构如下图所示。

        

    Component:组件对象的接口即待装饰接口,可以给这些对象动态的添加职责;

    ConcreteComponent:具体的组件对象,实现了组件接口。该对象通常就是被装饰器装饰的原始对象,可以给这个对象添加职责;

    Decorator:所有装饰器的父类,需要定义一个与组件接口一致的接口(主要是为了实现装饰器功能的复用,即具体的装饰器A可以装饰另外一个具体的装 饰器B,因为装饰器类也是一个Component),并持有一个Component对象,该对象其实就是被装饰的对象。如果不继承组件接口类,则只能为某 个组件添加单一的功能,即装饰器对象不能在装饰其他的装饰器对象。

    ConcreteDecorator:具体的装饰器类,实现具体要向被装饰对象添加的功能。用来装饰具体的组件对象或者另外一个具体的装饰器对象。


(1) 待装饰的接口Component

package pattern.decorator;
public interface Component {
    public void operation();
}

(2)具体的组件对象, 俗称的原始对象,或者说待装饰对象

package pattern.decorator;

public class ConcreteComponent implements Component {

    public void operation() {

        System.out.println("原始类的方法");

    }

}


(3)装饰器父类, 它主要是为装饰器定义了我们需要装饰的目标是什么。

package pattern.decorator;

public abstract class Decorator implements Component {

    protected Component component;

    public Decorator(Component component) {

        super();

        this.component = component;

    }

}


(4)装饰器1

package pattern.decorator;

public class Decorator1 extends Decorator {

    public Decorator1(Component component) {

        super(component);

    }

    public void method1() {

        System.out.println("被装饰器1扩展的功能");

    }

    public void operation() {

        System.out.println("针对原始方案增加做第1次装饰");

        component.operation();

        System.out.println("第1次装饰结束");

    }

}


(5)装饰器2

package pattern.decorator;

public class Decorator2 extends Decorator {

    public Decorator2(Component component) {

        super(component);

    }

    public void method2() {

        System.out.println("被装饰器2扩展的功能");

    }

    public void operation() {

        System.out.println("针对原始方案增加做第2次装饰");

        component.operation();

        System.out.println("第2次装饰结束");

    }

}


(6)客户端

package pattern.decorator;

public class Client {

    /**

     * @param args

     */

    public static void main(String[] args) {

        Component component = new ConcreteComponent();// 原来的对象

        Decorator1 decorator1 = new Decorator1(component);

        decorator1.method1();

        decorator1.operation();

        Decorator2 decorator2 = new Decorator2(component);

        decorator2.method2();

        decorator2.operation();

        Decorator decorator = new Decorator2(new Decorator1(component));

        decorator.operation();

    }

}



输出结果

被装饰器1扩展的功能

针对原始方案增加做第1次装饰

原始类的方法

第1次装饰结束

被装饰器2扩展的功能

针对原始方案增加做第2次装饰

原始类的方法

第2次装饰结束

针对原始方案增加做第2次装饰

针对原始方案增加做第1次装饰

原始类的方法

第1次装饰结束

第2次装饰结束



3、IO与装饰器模式


package pattern.decorator;

import java.io.BufferedInputStream;

import java.io.BufferedReader;

import java.io.DataInputStream;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.LineNumberReader;

import java.io.PushbackInputStream;

import java.io.PushbackReader;

public class IOTest {

    /*

     * test.txt内容: hello jd!

     */

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        // 文件路径可自行更换

        final String filePath = "d:/test.txt";

        // InputStream相当于被装饰的接口或者抽象类,FileInputStream相当于原始的待装饰的对象,FileInputStream无法装饰InputStream

        // 另外FileInputStream是以只读方式打开了一个文件,并打开了一个文件的句柄存放在FileDescriptor对象的handle属性

        // 所以下面有关回退和重新标记等操作,都是在堆中建立缓冲区所造成的假象,并不是真正的文件流在回退或者重新标记

        InputStream inputStream = new FileInputStream(filePath);

        final int len = inputStream.available();// 记录一下流的长度

        System.out.println("FileInputStream不支持mark和reset:" + inputStream.markSupported());

        System.out.println("---------------------------------------------------------------------------------");

        /* 下面分别展示三种装饰器的作用BufferedInputStream,DataInputStream,PushbackInputStream,下面做了三个装饰器的功能演示 */ 

        // 首先装饰成BufferedInputStream,它提供我们mark,reset的功能

        /*BufferedInputStream是一个带有缓冲区域的InputStream,它的继承体系如下:

                InputStream

                |__FilterInputStream

                        |__BufferedInputStream

        */

        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);// 装饰成 BufferedInputStream

        System.out.println("BufferedInputStream支持mark和reset:" + bufferedInputStream.markSupported());

        bufferedInputStream.mark(0);// 标记一下

        char c = (char) bufferedInputStream.read();

        System.out.println("文件的第一个字符:" + c);

        bufferedInputStream.reset();// 重置

        c = (char) bufferedInputStream.read();// 再读

        System.out.println("重置以后再读一个字符,依然会是第一个字符:" + c);

        bufferedInputStream.reset();

        System.out.println("---------------------------------------------------------------------------------");

        // 装饰成 DataInputStream,我们为了又使用DataInputStream,又使用BufferedInputStream的mark reset功能,所以我们再进行一层包装

        // 注意,这里如果不使用BufferedInputStream,而使用原始的InputStream,read方法返回的结果会是-1,即已经读取结束

        // 因为BufferedInputStream已经将文本的内容读取完毕,并缓冲到堆上,默认的初始缓冲区大小是8192B

        DataInputStream dataInputStream = new DataInputStream(bufferedInputStream);

        dataInputStream.reset();// 这是BufferedInputStream提供的功能,如果不在这个基础上包装会出错

        System.out.println("DataInputStream现在具有readInt,readChar,readUTF等功能");

        int value = dataInputStream.readInt();// 读出来一个int,包含四个字节

        // 我们转换成字符依次显示出来,可以看到文件的前四个字符

        String binary = Integer.toBinaryString(value);

        int first = binary.length() % 8;

        System.out.print("使用readInt读取的前四个字符:");

        for (int i = 0; i < 4; i++) {

            if (i == 0) {

                System.out.print(((char) Integer.valueOf(binary.substring(0, first), 2).intValue()));

            } else {

                System.out.print(((char) Integer.valueOf(binary.substring((i - 1) * 8 + first, i * 8 + first), 2).intValue()));

            }

        }

        System.out.println();

        System.out.println("---------------------------------------------------------------------------------");

        // PushbackInputStream无法包装BufferedInputStream支持mark reset,因为它覆盖了reset和mark方法

        // 因为流已经被读取到末尾,所以我们必须重新打开一个文件的句柄,即FileInputStream

        inputStream = new FileInputStream(filePath);

        PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream, len);// 装饰成 PushbackInputStream

        System.out.println("PushbackInputStream装饰以后支持退回操作unread");

        byte[] bytes = new byte[len];

        pushbackInputStream.read(bytes);// 读完了整个流

        System.out.println("unread回退前的内容:" + new String(bytes));

        pushbackInputStream.unread(bytes);// 再退回去

        bytes = new byte[len];// 清空byte数组

        pushbackInputStream.read(bytes);// 再读

        System.out.println("unread回退后的内容:" + new String(bytes));

        System.out.println("---------------------------------------------------------------------------------");

        /* 以上有两个一层装饰和一个两层装饰,下面我们先装饰成Reader,再进行其它装饰 */

        // 由于之前被PushbackInputStream将流读取到末尾,我们需要再次重新打开文件句柄

        inputStream = new FileInputStream(filePath);

        InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");// 先装饰成InputStreamReader

        System.out.println("InputStreamReader有reader的功能,比如转码:" + inputStreamReader.getEncoding());

        System.out.println("---------------------------------------------------------------------------------");

        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);// 我们进一步在reader的基础上装饰成BufferedReader

        System.out.println("BufferedReader有readLine等功能:" + bufferedReader.readLine());

        System.out.println("---------------------------------------------------------------------------------");

        LineNumberReader lineNumberReader = new LineNumberReader(inputStreamReader);// 我们进一步在reader的基础上装饰成LineNumberReader

        System.out.println("LineNumberReader有设置行号,获取行号等功能(行号从0开始),当前行号:" + lineNumberReader.getLineNumber());

        System.out.println("---------------------------------------------------------------------------------");

        // 此处由于刚才被readLine方法将流读取到末尾,所以我们再次重新打开文件句柄,并需要将inputstream再次包装成reader

        inputStreamReader = new InputStreamReader(new FileInputStream(filePath));

        PushbackReader pushbackReader = new PushbackReader(inputStreamReader, len);// 我们进一步在reader的基础上装饰成PushbackReader

        System.out.println("PushbackReader是拥有退回操作的reader对象");

        char[] chars = new char[len];

        pushbackReader.read(chars);

        System.out.println("unread回退前的内容:" + new String(chars));

        pushbackReader.unread(chars);// 再退回去

        chars = new char[len];// 清空char数组

        pushbackReader.read(chars);// 再读

        System.out.println("unread回退后的内容:" + new String(chars));

    }

}



阅读更多
想对作者说点什么? 我来说一句

单例窗体实现

2012年05月11日 12KB 下载

Spring In Action-3.2@Scope单例、多例Bean

2017年09月06日 13.59MB 下载

设计模式——单例实现

2017年06月29日 26KB 下载

Java单例模式的全面总结

2010年12月15日 78KB 下载

Singleton.cs

2017年04月19日 546B 下载

抽象工厂模式.net事例

2009年07月08日 167KB 下载

单例多例模式

2017年04月27日 13KB 下载

单例代码

2011年12月08日 2KB 下载

没有更多推荐了,返回首页

不良信息举报

单例

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭