设计模式——Decorator(装饰器)设计模式

时间:2024-12-06 21:21:44

摘要

本文介绍了装饰器设计模式,这是一种结构型设计模式,允许在不修改对象的情况下动态地为其添加功能。文章概述了装饰器模式的定义、作用、优点、缺点、类图实现和使用场景,强调了其在功能拓展、动态行为改变、避免类爆炸问题、增强现有对象功能、组合独立功能以及功能与行为解耦方面的优势。

1. 装饰器设计模式是什么

1.1. 装饰器设计模式

动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。

1.2. 装饰器设计模式作用

1.2.1. 装饰模式的优点:

  1. 使用装饰模式来实现扩展比继承更加灵活,它可以在不需要创造更多子类的情况下,将对象的功能加以扩展。
  2. 可以动态地给一个对象附加更多的功能。
  3. 可以用不同的装饰器进行多重装饰,装饰的顺序不同,可能产生不同的效果。
  4. 装饰类和被装饰类可以独立发展,不会相互耦合;装饰模式相当于是继承的一个替代模式。

1.2.2. 装饰模式的缺点:

  1. 与继承相比,用装饰的方式拓展功能更加容易出错,排错也更困难。对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

2. 装饰器模式类图实现

上图中的 Component 是一个抽象类,代表具有某中功能(function)的组件,ComponentImplA 和 ComponentImplB 分别是其具体的实现子类。Decorator 是 Component 装饰器,里面有一个 Component 的对象 decorated,这就是被装饰的对象,装饰器可为被装饰对象添加额外的功能或行为(addBehavior)。DecoratorImplA 和 DecoratorImplB 分别是两个具体的装饰器(实现子类)。

这样一种模式很好地将装饰器与被装饰的对象进行解耦。

3. 装饰器模式使用场景

装饰器模式(Decorator Pattern)是结构型设计模式之一,它允许在不改变对象自身的情况下,动态地为对象添加额外的功能。这个模式通常用于以下几种场景:

3.1. 功能拓展

如果你希望在运行时对一个对象的功能进行扩展,而不想通过继承的方式增加多个子类,装饰器模式是非常合适的。它可以在不影响原有类的情况下,通过多个装饰器逐步为对象添加功能。

示例场景:假设你有一个“咖啡”类,提供基本的咖啡功能。通过装饰器模式,你可以动态地添加不同的配料(比如牛奶、糖浆、奶油等),而不需要改变原始的“咖啡”类。每种配料可以是一个独立的装饰器类。

3.2. 动态改变对象行为

在一些系统中,可能需要根据不同的条件或需求来动态改变对象的行为,装饰器模式能够很好地支持这种需求。

示例场景:例如,在一个游戏中,不同的玩家可能会有不同的装备,装备带来不同的属性加成。你可以用装饰器来为玩家动态增加属性,而不需要为每种装备写一个独立的类。

3.3. 避免类爆炸问题

在某些情况下,通过继承来扩展功能会导致类的数量暴增,这时装饰器模式可以通过组合而不是继承来达到同样的目的,从而避免类层次过深。

示例场景:比如,一个支付系统可能有不同的支付方式,如银行卡支付、支付宝支付等,每种支付方式可能有不同的验证、支付记录等需求。如果使用继承,会产生大量的子类,而装饰器模式可以避免这一问题。你可以为每种支付方式添加验证、记录等功能,而不需要为每种功能分别创建子类。

3.4. 增强现有对象功能

如果你需要给一个已经存在的类增加一些额外的功能,但又不希望改变原类的实现或破坏现有的功能,可以使用装饰器模式。

示例场景:比如一个文件处理类,你可能想在它的基础上添加日志功能、缓存功能等,但又不希望修改原有的类结构。你可以创建不同的装饰器类,分别为文件处理类添加日志记录、缓存等功能。

3.5. 组合多个独立功能

装饰器模式允许多个装饰器独立地组合使用,这样可以根据需要灵活地添加、删除功能,而不需要修改原始对象或创建大量的子类。

示例场景:在一个用户认证系统中,你可以为用户添加多种认证方式(如密码认证、指纹认证、短信验证码等)。这些认证功能可以通过不同的装饰器来实现,用户的认证对象可以在运行时按需组合不同的认证方式。

3.6. 功能和行为的解耦

装饰器模式使得功能的增加与原始类解耦,不必修改原有的类逻辑。它实现了关注点分离,让功能的扩展和主类逻辑独立。

示例场景:假设你有一个日志系统,原始的系统类只负责核心业务,而日志功能可以作为一个装饰器来动态加入,这样日志和核心业务逻辑就被解耦开来。

4. 装饰器模式示例

4.1. 定义 Person

Person 是所有角色的基类,包含基本属性和方法。

public abstract class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void wear() {
        System.out.println("我的着装是:");
    }
}

4.2. 定义具体角色类

角色类 EngineerTeacher 扩展自 Person,并增加了各自的特殊属性和方法。

public class Engineer extends Person {
    private String skill;

    public Engineer(String name, String skill) {
        super(name);
        this.skill = skill;
    }

    public String getSkill() {
        return skill;
    }

    @Override
    public void wear() {
        System.out.println("我是" + getSkill() + "工程师" + getName());
        super.wear();
    }
}

public class Teacher extends Person {
    private String title;

    public Teacher(String name, String title) {
        super(name);
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    @Override
    public void wear() {
        System.out.println("我是" + getName() + getTitle());
        super.wear();
    }
}

4.3. 定义装饰器类

装饰器基类 ClothingDecorator 实现了装饰逻辑。

public abstract class ClothingDecorator extends Person {
    protected Person decoratedPerson;

    public ClothingDecorator(Person person) {
        super(person.getName());
        this.decoratedPerson = person;
    }

    @Override
    public void wear() {
        decoratedPerson.wear();
    }
}

4.4. 定义具体装饰器

每个具体装饰器类负责装饰 Person 对象,扩展其 wear 方法。

public class CasualPantDecorator extends ClothingDecorator {
    public CasualPantDecorator(Person person) {
        super(person);
    }

    @Override
    public void wear() {
        super.wear();
        System.out.println("一条卡其色休闲裤");
    }
}

public class BeltDecorator extends ClothingDecorator {
    public BeltDecorator(Person person) {
        super(person);
    }

    @Override
    public void wear() {
        super.wear();
        System.out.println("一条银色针扣头的黑色腰带");
    }
}

public class LeatherShoesDecorator extends ClothingDecorator {
    public LeatherShoesDecorator(Person person) {
        super(person);
    }

    @Override
    public void wear() {
        super.wear();
        System.out.println("一双深色休闲皮鞋");
    }
}

public class KnittedSweaterDecorator extends ClothingDecorator {
    public KnittedSweaterDecorator(Person person) {
        super(person);
    }

    @Override
    public void wear() {
        super.wear();
        System.out.println("一件紫红色针织毛衣");
    }
}

public class WhiteShirtDecorator extends ClothingDecorator {
    public WhiteShirtDecorator(Person person) {
        super(person);
    }

    @Override
    public void wear() {
        super.wear();
        System.out.println("一件白色衬衫");
    }
}

public class GlassesDecorator extends ClothingDecorator {
    public GlassesDecorator(Person person) {
        super(person);
    }

    @Override
    public void wear() {
        super.wear();
        System.out.println("一副方形黑框眼镜");
    }
}

4.5. 测试

测试装饰器模式的效果。

public class DecoratorPatternTest {
    public static void main(String[] args) {
        // 创建基础对象
        Person engineer = new Engineer("张三", "软件开发");

        // 装饰对象
        Person dressedEngineer = new GlassesDecorator(
            new WhiteShirtDecorator(
                new KnittedSweaterDecorator(
                    new CasualPantDecorator(
                        new BeltDecorator(
                            new LeatherShoesDecorator(engineer))))));

        // 输出最终装扮
        dressedEngineer.wear();
    }
}

运行上述代码,输出结果如下:

复制代码
我是软件开发工程师张三
我的着装是:
一双深色休闲皮鞋
一条银色针扣头的黑色腰带
一条卡其色休闲裤
一件紫红色针织毛衣
一件白色衬衫
一副方形黑框眼镜

博文参考

《软件设计模式》