设计模式 – 装饰器模式
作用
提供了将对象的行为动态的添加到系统现有类的功能,
这是名字的由来,装饰二字
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);
两个等价