设计模式 - 装饰器模式

作用

提供了将对象的行为动态的添加到系统现有类的功能,

这是名字的由来,装饰二字

JavaScript

使用js书写装饰器模式

// 车辆vehicle构造函数
function vehicle(vehicleType){
    // 默认值
    this.vehicleType = vehicleType || "car";
    this.model = "default";
    this.license = "00000-00000";
}

// 测试构造函数
var testInstance = new vehicle("car");
console.log(testInstance);

// 创建一个实例进行装饰
var truck = new vehicle("truck");

// 然后给其装饰上新的功能
truck.setModel = function(modelName){
    this.model = modelName;
}

truck.setColor = function(color){
    this.color = color;
}

上方完成了装饰器模式,使用构造函数,生成对象以后,在不影响构造函数的代码的同时,给新的对象,添加上了新的方法。即装饰

使用多个装饰对象

function MacBook(){
    this.cost = () => {
        return 997;
    }
    this.screenSize = () => {
        return 11.6;
    }
}

// 装饰1
function Memory(macbook){
    let v = macbook.cost();
    // 重写父类的方法
    macbook.cost = () => {
        return v + 75;
    }
}

// 装饰2
function Engtaving(macbook){
    let v = macbook.cost();
    macbook.cost = () => {
        return v + 87;
    }
}

function Insurance(macbook){
    let v = macbook.cost();
    macbook.cost = () => {
        return v + 100;
    }
}

var mb = new MacBook();
Memory(mb);
Engtaving(mb);
Insurance(mb);

console.log(mb.cost());
console.log(mb.screenSize());

核心

在不修改以有类的前提下,增加对对象的行为的添加,即为装饰对象。

Java

好啦。扩展到Java
以老王买水果为栗子

//老王被装饰的对象
public interface Person{
    // 计算累计消费
    public Double cost();
    public void show();
}

// 定义老王
public class LaoWang implements Person {
    @Override
    public Double cost(){
        return 0.0;    // 没有买任何内容
    }

    @Override
    public void show(){
        System.out.println("我是老王")
    }
}

// 下面书写装饰器,即要实现对老王的行为的动态更改,即更改cost内中的返回值,即新生成的对象要重写进行重写
// 由于是超类,需要对类进行抽象,使用抽象类,同时需要实现Person的接口
public abstract class ClothesDecorator implements Person{
    // 装饰器中要使用的被装饰的对象,在构造方法中传入
    // 使用对于本包和子类可见的访问控制
    protected Person person;    // 符合里氏替换原则,父能替换掉子的,依旧能工作,此时保留下来的只是接口中的内容,详细参考虚函数。C++中接口使用虚函数来实现,即运行的时候才能确认

    public ClothesDecorator(Person person){
        this.person = person;
    }
}

// 接着,进行装饰
public class Jacket extends ClothesDecorator{
    public Jacket(Person person){
        super(person);    // 先调用抽象类中构造方法,完成对对要装饰的那一部分的保存,即完成对装饰部分的指向,实际上接口底层为虚函数,其目的是完成指针的指向
    }

    @Override
    public void show(){
        person.show();    // 通过指针调用对象内部的show方法,并完成对齐的更改等
        System.out.println("穿上夹克" + this.cost());
    }

    @Override
    public Double cost(){
        return person.cost() + 100; // 夹克100元,实现累加
    }

}

public class Hat extends ClothesDecorator{
    public void show(){
        person.show();    // 执行已有的
        System.out.println("戴上帽子" + this.cost());
    }

    @Override
    public Double cost(){
        return person.cost()
    }
}
C++中接口使用虚函数

然后完成对已经生成的对象的修改


package demo1;

public class Test {
    public static void main(String[] args) {
        Person laowang = new LaoWang();    // 子能用的地方,换成父也能用,
        // 或者定义了一个在栈中储存的laowang变量,该变量的类型为Person为一个地址表,仅仅能保存已经定义的两个方法的指针,用来指向在堆中保存的方法,右值,声明了一个对象,该对象在堆中被完整的声明,只有两个方法被在栈中的指针,完成指向
        laowang = new Jacket(laowang);    // 送进Jacket装饰器进行装饰,
        
    }
}

好啦,这就是一次装饰类

扩展

回顾老王穿衣的代码。更改如下

Person laowang = new Jacket(new LaoWang());

Person laowang = new LaoWang();
laowang = new Jacket(laowang);

两个等价


小小____
435 声望110 粉丝

哇哈~我在那~这是哪~每日连11问