结构型-装饰器模式

结构型,装饰,模式 · 浏览次数 : 98

小编点评

**装饰器模式** 装饰器模式是一种编程模式,它允许我们通过对原有对象进行包装,使其可以动态具有更多功能。这种模式不影响原有功能可同时装饰多个对象,同时又不改变其结构。 **优点:** * 不影响原有功能可同时装饰多个对象 * 允许通过对原有对象进行包装,使其可以动态具有更多功能 * 不改变原有代码的结构 **使用装饰器模式的场景:** * 给业务代码附加非业务相关功能 * 扩展现有对象的功能 **例子:** ```js // 装饰器模式 function decoratorRun (fn) { return function (...args) { // 调用原有函数 console.log('执行原有函数'); // 执行装饰器的逻辑 return fn.apply(this, args); }; } // 使用装饰器扩展方法 function run() { console.log('执行方法'); } // 使用装饰器扩展属性 function objectWithAttribute() { return { isTestable: true, // 其他属性和方法 }; } // 使用装饰器动态添加属性 objectWithAttribute.isTestable = false; ``` **结论:** 装饰器模式是一种非常灵活的模式,它可以用于给业务代码附加任何非业务相关功能。这种模式非常适合创建可扩展且易维护的代码。

正文

定义

  如果希望动态给某个类添加一些属性或者方法,但是你又不希望这个类派生的对象受到影响,那么装饰器模式就可以给你带来这样的体验。

它的定义就是在不改变原对象的基础上,通过对其进行包装拓展,使得原有对象可以动态具有更多功能,从而满足用户的更复杂需求

举个例子,一部手机,你可以买各种花里胡哨的手机壳等,这些手机壳其实就起到了装饰的作用,对手机本身的功能没有影响。

那么装饰器模式的特点就来了:

  1. 不影响原有功能
  2. 可同时装饰多个

js模拟装饰模式

向一个现有对象添加新的功能,同时又不改变其结构。

如我在跑步,但是我想一边跑步一边听歌。我们通常很快速的下写如下代码

/*
 如跑步时我想听音乐
*/
function run() {
  console.log('joel run')
}

// 一般改成如下:
function run() {
  console.log('joel run')
  // 听音乐代码 ...
}
// 或者把听音乐抽成一个方法
function music() {
  console.log('听歌')
}
function run() {
  console.log('joel run')
  music()
}
// 以上都违反来关闭原则

上面的代码都需要在原有的代码上面做调整,这样违反了关闭原则,按照装饰模式的定义,我们可以用装饰器模式扩展我们的跑步方法。

如下把上面的代码改成符合装饰模式思想

/***************************** 1、最简单的装饰 **************************/
// 1.1 入口套一层函数
function decoratorRun (fn) {
  fn()
  music()
}

decoratorRun(run)

// 1.2 中间变量保存引用
function run () {
  console.log('joel run')
}
function music() {
  console.log('听歌')
}
let _run = run;
run = function () {
  _run()
  music()
}
run()
// 上面两种都是固定了调用的位置不太灵活,并没有当成一个工具函数来使用

/***************************** 2、工具函数 **************************/
// 装饰fn函数,利用闭包特点
const decoratorRun1 = function (fn, afterFn) {
  return function (...args) {
    const res = fn.apply(this, args)
    afterFn.apply(this, args );
    return res;
  }
}
function run() {
  console.log('joel run')
}
function music(name) {
  console.log(`我正在听${name},很好听。`)
}
const runAndMusic = decoratorRun1(run,music);
runAndMusic('孤勇者');

/************************* 3、原型链, 把入口挂载到Function原型上*********/
Function.prototype.before = function (beforeFn) {
  const _self = this;
  return function (...args) {
    beforeFn.apply(this, args);
    return _self.apply(this, args);
  }
}

Function.prototype.after = function (afterFn) {
  const _self = this;
  return function (...args) {
    const result = _self.apply(this, args);
    afterFn.apply(this, args);
    return result;
  }
}
function run() {
  console.log('joel run')
}
function music(name) {
  console.log(`我正在听${name},很好听。`)
}
const runAndMusic1 = run.after(music)
runAndMusic1('孤勇者')

/***************************** 4、es7+ 装饰器写法 **************************/
@testable
class MyTestableClass {
  // ...
}

function testable(target) {
  target.isTestable = true;
}

MyTestableClass.isTestable // true

js 中的装饰器

在最新版本的es next 中,引入了 Decorator (装饰器的语法),从语言语法层面帮助我们快速的扩展我们的类(class)的功能。

function testAble(isTestable) {
    return function(target) {
        target.isTestable = isTestable;
    }
}

@testAble(true)
class MyTestClass {}
MyTestClass.isTestable; // true

@testAble(false)
class MyTestClass1 {}
MyTestClass1.isTestable; // false

你要知道的AOP概念

在上面模拟装饰器的时候,把函数挂载到Function原型上,有那么一点点AOP的思路。

AOP为Aspect Oriented Programming的缩写,指面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。

AOP 是一种编程范式,通俗的可以理解为这种在运行时,编译时,类和方法加载时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。

如上图从横向角度来分析,业务1-3都需要日志,安全、其他等这种与业务无关的代码逻辑,这个时候我们把这种代码抽离出来,在动态的插入的技术就是面向切面编程。

AOP主要把业务逻辑无关的功能进行抽离,这些与业务逻辑无关的内容如日志打印、数据统计、异常处理、权限控制等各个部分进行隔离,在通过动态注入的方式注入到业务代码中。这样做既保证了业务内部高内聚,模块之间低耦合,方便管理与业务无关的模块,有利于未来的可操作性和可维护性。

面向切面编程(AOP)是一种通过横切关注点(Cross-cutting Concerns)分离来增强代码模块性的方法,它能够在不修改业务主体代码的情况下,对它添加额外的行为。

优点是:这样的做法,对原有代码毫无入侵性

AOP场景

AOP采取横向思考的思维,横向抽取机制,取代了传统纵向继承体系重复性代码的编写方式(例如性能监视、事务管理、安全检查、缓存、日志记录等)。

在软件系统设计的时候,我们需要把一个大的系统按照业务功能进行拆分,做到高内聚、低耦合。

但是呢,拆分之后会产生一些通用性的东西,比如日志,安全,事务,性能统计等,这些非功能性需求。

  1. 记录日志
  2. 监控方法运行时间 (监控性能)
  3. 权限控制
  4. 缓存优化 (第一次调用查询数据库,将查询结果放入内存对象, 第二次调用, 直接从内存对象返回,不需要查询数据库 )
  5. 事务管理 (调用方法前开启事务, 调用方法后提交或者回滚、关闭事务 )

AOP、装饰器模式

 AOP 与装饰器都是解决一样的问题,隔离业务逻辑无关的代码快。

装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为如有日志、性能测试、事务处理等,在 JavaScript 中,我们可以通过装饰者模式来实现 AOP,但是两者并不是一个维度的概念。 AOP 是一种编程范式,而装饰者是一种设计模式。 

小结

  1. 装饰者模式非常适合给业务代码附加非业务相关功能
  2. 装饰者模式非常适合无痛扩展别人的代码
  3. 装饰器模式还真的可以让代码变得优雅

与结构型-装饰器模式相似的内容:

结构型-装饰器模式

定义 如果希望动态给某个类添加一些属性或者方法,但是你又不希望这个类派生的对象受到影响,那么装饰器模式就可以给你带来这样的体验。 它的定义就是在不改变原对象的基础上,通过对其进行包装拓展,使得原有对象可以动态具有更多功能,从而满足用户的更复杂需求。 举个例子,一部手机,你可以买各种花里胡哨的手机壳等

设计模式学习(九):装饰器模式

设计模式学习(九):装饰器模式 作者:Grey 原文地址: 博客园:设计模式学习(九):装饰器模式 CSDN:设计模式学习(九):装饰器模式 装饰器模式 装饰器模式是一种结构型模式。 顾名思义,就是对某个方法或者对象进行装饰,举个简单的例子,有个圆形类 Circle,我需要把这个圆形的涂上红色,其实

软件设计模式系列之十一——装饰模式

装饰模式属于结构型设计模式,它通过将对象包装在装饰器类中来动态地添加额外的行为,而不需要修改原始对象的代码。这个模式以透明的方式向对象添加功能,从而使您可以根据需要组合各种功能。

设计模式之装饰模式(学习笔记)

定义 装饰模式(Decorator Pattern),又称为包装模式,是一种结构型设计模式。它允许在不改变现有对象结构的情况下,动态地添加新的功能。通过将每个功能封装在单独的装饰器类中,并且这些装饰器类通过引用原始对象来实现功能的组合,从而提供了灵活性和可扩展性的优势。装饰模式避免了通过继承方式增加

【23种设计模式】适配器模式(六)

## 前言 从今天开始我们开始讲【结构型】设计模式,【结构型】设计模式有如下几种:**适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式、代理模式**。【创建型】的设计模式解决的是对象创建的问题,那【结构型】设计模式解决的是类和对象的组合关系的问题。 今天我们就开始讲【结构型】设计模式里面

当装饰者模式遇上Read Through缓存,一场技术的浪漫邂逅

在《经验之谈:我为什么选择了这样一个激进的缓存大Key治理方案》一文中,我提到在系统中使用的缓存是旁路缓存模式,有读者朋友问,有没有用到过其他的缓存模式,本文将结合一个我曾经工作中的案例,使用装饰者模式实现Read Through缓存模式,助你轻松掌握设计模式和缓存。

< Python全景系列-3 > Python控制流程盘点及高级用法、神秘技巧大揭秘!

全面深入地介绍 Python 的控制流程,包括条件语句、循环结构和异常处理等关键部分,尤其会将列表解析、生成器、装饰器等高级用法一网打尽。此外,我还将分享一些独特的见解和研究发现,希望能给你带来新的启发。文章的结尾,我们将有一个 "One More Thing" 环节,我会分享一个很特别但又很少人知道的有用的 Python 控制流程的技巧。

2.6 PE结构:导出表详细解析

导出表(Export Table)是Windows可执行文件中的一个结构,记录了可执行文件中某些函数或变量的名称和地址,这些名称和地址可以供其他程序调用或使用。当PE文件执行时Windows装载器将文件装入内存并将导入表中登记的DLL文件一并装入,再根据DLL文件中函数的导出信息对可执行文件的导入表(IAT)进行修正。

2.1 PE结构:文件映射进内存

PE结构是`Windows`系统下最常用的可执行文件格式,理解PE文件格式不仅可以理解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,在任何一款操作系统中,可执行程序在被装入内存之前都是以文件的形式存放在磁盘中的,在早期DOS操作系统中,是以COM文件的格式存储的,该文件格式限制了只能使用代码段,堆栈寻址也被限制在了64KB的段中,由于PC芯片的快速发展这种文件格式极大的制

驱动开发:内核PE结构VA与FOA转换

本章将继续探索内核中解析PE文件的相关内容,PE文件中FOA与VA,RVA之间的转换也是很重要的,所谓的FOA是文件中的地址,VA则是内存装入后的虚拟地址,RVA是内存基址与当前地址的相对偏移,本章还是需要用到`《驱动开发:内核解析PE结构导出表》`中所封装的`KernelMapFile()`映射函数,在映射后对其PE格式进行相应的解析,并实现转换函数。