单例

参考: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));

    }

}



Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值