博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式笔记(四)——装饰者模式
阅读量:5740 次
发布时间:2019-06-18

本文共 7668 字,大约阅读时间需要 25 分钟。

hot3.png

1. 是什么——定义

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

2. 为什么——特点

1)  装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。

2)  装饰对象包含一个真实对象的引用。

3)  装饰对象接受所有来自客户端的请求,它把这些请求转发给真实的对象。

4)  装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

3. 什么时候用——适用性

1)  需要扩展一个类的功能,或给一个类添加附加职责。

2)  需要动态的给一个对象添加功能,这些功能可以再动态的撤销。

3)  需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。

4)  当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

4. UML图

194516_vzA2_3041734.png
 

5. 怎么用——使用方法

需求:

模拟人穿衣服

5.1  没有任何原则的初始设计

public class Demo1 {    public static void main(String[] args) {        Person person = new Person();        person.setName("二哈");        person.wearTshirt();        person.wearJeans();        person.wearShoes();    }}class Person {    private String name;    public void wearTshirt() {        System.out.println(name + "穿了一件T恤");    }    public void wearSweater() {        System.out.println(name + "穿了一件毛衣");    }    public void wearJeans() {        System.out.println(name + "穿了一条裤子");    }    public void wearShoes() {        System.out.println(name + "穿了一双鞋");    }//    public ..... -- 违反开放-封闭原则    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

可以看到,如果要增加新的衣服,就需要扩展方法,这就违背了“开放-封闭原则”。

5.2  将“服装”抽象

public class Demo2 {    public static void main(String[] args) {        Person person = new Person();        Clothes Tshirt = new TShirt();        Clothes shoes = new Shoes();        Clothes superman = new SupermanClothes();        person.wear(superman);        person.wear(Tshirt);        person.wear(shoes);    }}class Person {    private String name;    public void wear(Clothes clothes) {        System.out.println(name + "穿了" + clothes.getName());    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}abstract class Clothes {    private String name;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}class TShirt extends Clothes {    }class Shoes extends Clothes {    }class SupermanClothes extends Clothes {    }

这样确实达到效果了,但每次穿衣服的时候总感觉是当着众人的面穿,而且逻辑也不对:每次都是人在穿,但实际情况是:穿了一件后,下一件衣服是套在原来那件衣服上!需要改进!

5.3  使用装饰者模式

public class Demo3 {    public static void main(String[] args) {        Person person = new Person();        person.setName("二狗");        Clothes tshirt = new Tshirt();        person.wear(tshirt);        Clothes coat = new Coat();        tshirt.wear(coat);        coat.show();    }}class Person {    private String name;    public void show() {        System.out.println(name);    }    public void wear(Clothes clothes) {        clothes.setWornClothes(this);    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}abstract class Clothes extends Person {    private Person wornClothes; //要被穿的衣服/人    private String clothesName;    @Override    public void show() {        System.out.println(clothesName + "\t");        wornClothes.show();    }    public String getClothesName() {        return clothesName;    }    public void setClothesName(String clothesName) {        this.clothesName = clothesName;    }    public Person getWornClothes() {        return wornClothes;    }    public void setWornClothes(Person wornClothes) {        this.wornClothes = wornClothes;    }}class Tshirt extends Clothes {    public Tshirt () {        this.setClothesName("T恤");    }}class Coat extends Clothes {    public Coat() {        this.setClothesName("大衣");    }}class Jeans extends Clothes {    public Jeans() {        this.setClothesName("裤子");    }}

 

6. 真实案例

需求:

a)  扩展BufferedReader类,使其每次读取文本信息时可以在文本前打印行号

b)  扩展BufferedReader类,使其每次读取文本信息时可以在文本后打印省略号

c)  扩展BufferedReader类,使其每次读取文本信息时可以在文本前和文本后打印引号

6.1  没有使用装饰者模式

import java.io.BufferedReader;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.Reader;public class Demo1 {    public static void main(String[] args) throws Exception {        BufferedReader br = new ReaderLineNumAndSusp(new InputStreamReader(new FileInputStream("D:/test.txt"), "GBK"));        String readline = null;        while ((readline = br.readLine()) != null) {            System.out.println(readline);        }        br.close();    }}//需求1:增强BufferedReader类,使每次读取的内容前面加上行号class ReaderLineNum extends BufferedReader {    private int lineNum = 1;    public ReaderLineNum(Reader in) {        super(in);    }    @Override    public String readLine() throws IOException {        String readline = super.readLine();        if (readline == null) {            return null;        }        readline = lineNum + readline;        lineNum++;        return readline;    }}//需求2:增强BufferedReader类,使每次读取的内容后面加上省略号class ReaderSusp extends BufferedReader {    public ReaderSusp(Reader in) {        super(in);    }    @Override    public String readLine() throws IOException {        String readline = super.readLine();        if (readline == null) {            return null;        }        readline = readline + "……";        return readline;    }}//需求3:增强BufferedReader类,使每次读取的内容前后加上双引号class ReaderQuot extends BufferedReader {    public ReaderQuot(Reader in) {        super(in);    }    @Override    public String readLine() throws IOException {        String readline = super.readLine();        if (readline == null) {            return null;        }        readline = "“" + readline + "”";        return readline;    }}//需求4:增强BufferedReader类,使每次读取的内容前加行号,内容后加省略号class ReaderLineNumAndSusp extends BufferedReader {    private int lineNum = 1;    public ReaderLineNumAndSusp(Reader in) {        super(in);    }    @Override    public String readLine() throws IOException {        String readline = super.readLine();        if (readline == null) {            return null;        }        readline = lineNum + readline + "……";        lineNum++;        return readline;    }}//需求5:。。。

6.2  使用装饰者模式

import java.io.BufferedReader;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.Reader;public class Demo2 {    public static void main(String[] args) throws Exception {        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D:/test.txt"), "GBK"));        BufferedReader brLineNum = new ReaderLineNum(br);        BufferedReader brSusp = new ReaderSusp(brLineNum);        String readline = null;        while ((readline = brSusp.readLine()) != null) {            System.out.println(readline);        }        brSusp.close();    }}class ReaderLineNum extends BufferedReader {    private int lineNum = 1;    private BufferedReader baseReader;    public ReaderLineNum(Reader in) {        super(in);        this.baseReader = (BufferedReader) in;    }    @Override    public String readLine() throws IOException {        String readline = baseReader.readLine();        if (readline == null) {            return null;        }        readline = lineNum + readline;        lineNum++;        return readline;    }}class ReaderSusp extends BufferedReader {    private BufferedReader baseReader;    public ReaderSusp(Reader in) {        super(in);        this.baseReader = (BufferedReader) in;    }    @Override    public String readLine() throws IOException {        String readline = baseReader.readLine();        if (readline == null) {            return null;        }        return readline + "……";    }}

可以实现三个类完成7种功能。

 

7. 装饰者模式与建造者模式的区别

建造者模式需要有一套完整的建造过程和顺序

装饰者模式更随意,灵活(哪怕内裤外穿。。。)

8. 装饰者模式与代理模式的区别

装饰者模式可以互相装饰,而代理模式有很明确的主从关系。

转载于:https://my.oschina.net/LinkedBear/blog/1787712

你可能感兴趣的文章
iOS开发-邮件发送
查看>>
/etc/resolv.conf文件详解
查看>>
【转】VC的MFC中重绘函数的使用总结(整理)
查看>>
JQuery日记_5.13 Sizzle选择器(六)选择器的效率
查看>>
oracle查看经常使用的系统信息
查看>>
Django_4_视图
查看>>
Linux的netstat命令使用
查看>>
lvm讲解,磁盘故障小案例
查看>>
大快网站:如何选择正确的hadoop版本
查看>>
经过这5大阶段,你离Java程序员就不远了!
查看>>
IntelliJ IDEA 连接数据库详细过程
查看>>
thymeleaf 学习笔记-基础篇
查看>>
PHP-X开发扩展
查看>>
android学习笔记——onSaveInstanceState的使用
查看>>
工作中如何做好技术积累
查看>>
怎么用sysLinux做U盘双PE+DOS??
查看>>
Spring Transactional
查看>>
shell脚本实例
查看>>
我的友情链接
查看>>
Windows Phone 7 隔离存储空间资源管理器
查看>>