面向对象设计模式学习总结之装饰器模式(Decorator)

文章目录

一、

    先来复习几个设计原则:

  • 封装变化
    (把会变化的部分取出并封装起来,以便以后可以轻易地改动或扩充此部分,而不影响不需要变化的其他部分。)
  • 针对接口编程,而不是针对实现编程。
  • 多用组合,少用继承。
    (因为使用组合建立系统具有很大的弹性,不仅可将算法封装成类,更可以在运行时动态地改变行为,只要组合的行为对象符合正确的接口标准即可。)

    利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在 运行时 动态地进行扩展。

    通过动态地组合组合对象,可以写新的代码添加新功能,而无须修改现有代码。既然没有改变现有代码,那么引进 bug 或产生意外副作用的机会将大幅减少。


【装饰者模式】体现的设计原则:
类应该对扩展开放,对修改关闭。


  • 装饰者和被装饰者有相同的超类。
  • 可以用一个或多个装饰类包装一个对象。
  • 既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装的)场合,可以用装饰过的对象代替它。
  • 装饰者可以在所委托被装饰者的行为之前 与/或 之后,加上自己的行为,以达到特定的目的。
  • 对象可以在任何时候装饰,所以可以在运行时动态地、不限量地用喜欢的装饰者来装饰对象。

定义装饰者模式:
    装饰者模式 动态地 将责任附加在对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。


    java.io 包中很多类都是装饰者。

在这里插入图片描述
    BufferedInputStream 及 LineNumberInputStream 都扩展自 FilterInputStream ,而 FilterInputStream 是一个抽象的装饰类。

在这里插入图片描述
    “输出”流的设计方式也是一样的,而且 Reader/Writer 流(作为基于字符数据的输入输出)和 输入/输出流的类 相当类似。
    但是 Java I/O 也引出装饰者模式的一个“缺点”:
    利用装饰者模式,常常造成设计中有大量的小类,数量实在太多,可能会造成使用此 API 的程序员的困扰。


    编写一个 Java I/O 装饰者:
要求:
    编写一个装饰者,把输入流内的所有大写字符转成小写。

public class LowerCaseInputStream extends FilterInputStream {
    public LowerCaseInputStream(InputStream in)
    {super(in);}

    public int read() throws IOException
    {
        int c=super.read();
        return (c==-1?c:Character.toLowerCase((char)c));
    }

    public int read(byte[] b,int offset,int len)throws IOException
    {
        int result=super.read(b,offset,len);
        for(int i=offset;i<offset+result;i++)
        {
            b[i]=(byte) Character.toLowerCase((char)b[i]);
        }
    return result;
        }
}

测试类:

public class InputTest {
    public static void main(String[] args) {
        int c;
        try
        {
            InputStream in=new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("/jia/files/hello.txt")));
        while((c=in.read())>=0)
        {
            System.out.print((char)(c));
        }
        in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

要点:

  • 继承属于 扩展 的形式之一,但不见得是达到弹性设计的最佳方式。
  • 在设计中,应该允许行为被扩展,而无须修改现有的代码。
  • 组合和委托可用于在运行时动态地加上新的行为。
  • 除了继承,装饰者模式也可以让我们扩展行为。
  • 装饰者模式意味着一群装饰者类,这些类用来包装具体组件。
    装饰者模式反映出被装饰的组件类型(事实上,题目具有相同的类型,都经过接口或继承实现)。
  • 装饰者可以在被装饰者的行为前面/与后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的。
  • 可以用无数个装饰者包装一个组件。
  • 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。
  • 装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。

二、

    为了多态,通过父类指针指向其具体子类,但是这会造成另一问题:
    当我们需要为子类添加新的职责,就必须向其父类添加一个这个功能的抽象接口,否则通过父类指针无法调用这个方法了。
    这样处于高层的父类就含有太多的的方法, 并且继承自这个父类的所有子类都不可避免继承了父类的这些接口,但是这些可能并不是所有子类所需要的。
    🌹为此我们采用组合的方式而不是继承方式。🌹
    当需要添加一个操作的时候就可以通过 Decorator 模式来解决。
    装饰模式通过一个包装对象,以对客户端透明的方式动态地给一个对象附加上更多的责任。

public class DecorationTest {
    public static void main(String[] args) {

        //采用这样的方式我们可以通过ConcreteDecorator的构造函数
        // 来确定传递某个具体的ConcreteComponent类

        Component component = new ConcreateComponet();
        component.operation();
        System.out.println();
        Component component1=new ConcreateDecorator1(new ConcreateComponet());
        component1.operation();
        System.out.println();
        Component component2=new ConcreateDecorator2(new ConcreateDecorator1(new ConcreateComponet()));
        component2.operation();
    }
}

// 抽象构件角色(Component):给出一个抽象接口,以规范准备接受附加责任的对象
interface Component
{
    public void operation();
}

class ConcreateComponet implements Component
{
    @Override
    public void operation() {
        System.out.println("拍照片");
    }
}

// 装饰角色(Decorator):持有一个构件(Component)对象的引用,并定义一个与抽象接口一致的接口
abstract class Decorator implements Component
{
    Component component;
public Decorator(Component component)
{this.component=component;}
}


//具体装饰角色(Concrete Decorator):负责给构件对象添加附加的责任
class ConcreateDecorator1 extends Decorator
{
public ConcreateDecorator1(Component component)
{super(component);}

    @Override
    public void operation() {
    component.operation();
    System.out.println("加滤镜");

    }
}

    class ConcreateDecorator2 extends Decorator
    {
        public ConcreateDecorator2(Component component)
        {super(component);}

        @Override
        public void operation() {
            component.operation();
            System.out.println("加贴纸");

        }
    }

运行结果:
拍照片

拍照片
加滤镜

拍照片
加滤镜
加贴纸

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值