zoukankan      html  css  js  c++  java
  • 装饰模式-designer-decorator-ts

    装饰者模式:

    npm init -y
    npm i vite -D
    'dev':'vite'
    npm run dev

    装饰者(decorator)模式能够在不改变对象自身的基础上,动态的给某个对象添加额外的职责,不会影响原有接口的功能。
    为了不改变原有的对象,我们可以把原对象放入到一个新的对象中以形成一个聚合对象。并且这些对象都有相同的接口。当我们使用这个装饰器对象时,会顺着请求链请求到上一个对象。对于用户来说,这个装饰器对象是透明的,用户可以依照这种方式一层一层的递归下去。

    es5:

    class Shape {
      constructor(name) {
        this.name = name
      }
    
      draw() {
        console.log(`draw ${this.name}`)
      }
    }
    
    class ColorDecorator {
      constructor(shape) {
        this.shape = shape
      }
    
      draw() {
        this.setColor()
        this.shape.draw()
      }
    
      setColor() {
        console.log(`color the ${this.shape.name}`)
      }
    }
    
    let circle = new Shape('circle')
    circle.draw()
    
    let decorator = new ColorDecorator(circle)
    decorator.draw()
    

    通过 ColorDecorator 对象实现了一个相同的 draw()方法,并在其中封装了 setColor()这个额外的职责方法,用户同样在调用 draw()方法时,也调用了上一个对象 Shape 的 draw()方法。我们可以以此类推,给对象添加上色,设置边框的一系列职责。

    实际上,装饰器也是一种包装器,把上个对象包装到某个对象中,层层包装

    es7 装饰着模式:

    class Shape {
      @log
      setColor(color) {
        return color
      }
    }
    
    function log(target, name, descriptor) {
      var oldValue = descriptor.value
    
      descriptor.value = function () {
        console.log(`Calling ${name} width `, arguments)
        return oldValue.apply(this, arguments)
      }
    
      return descriptor
    }
    
    const shape = new Shape()
    const color = shape.setColor('red')
    console.log('color', color)
    

    添加了一个 log 的装饰器,当执行 setColor()方法时,先去执行 log 方法,会自动打印日志,之后再返回到类的 setColor 方法

    项目构成

    app.ts,组件入口文件;
    index.ts:具体 TodoList 组件实现类文件,具体实现操作的步骤,增加,删除,切换状态;
    todoEvent.ts 事件处理函数;
    template.ts:view 模版视图部分

    组件入口模块文件:app.ts

    /**
     * 文件的入口文件:
     * 固定写法:一个模块
     */
    ;((doc) => {
      //1.获取dom,元素的获取
      //2.定义入口文件执行函数
      const init = (): void => {
        //3.执行绑定事件处理函数
        bindEvent()
      }
      //具体时间处理函数:
      function bindEvent(): void {
        //事件监听
      }
      //具体事件处理函数:
    
      //4.入口文件执行
      init()
    })(document)
    

    入口文件详解

    作为一个组件的入口,主要做一下工作: 1.定义模块,在模块中获取 dom 元素,给 dom 元素绑定事件监听 2.初始化创建类的实例, 3.在绑定的事件处理中调用类的方法进行处理

    todoList 类:

    主要是 dom 操作
    根据需求创建新增,删除,改变切换状态的操作 dom 的函数,定义好之后在类的方法具体的 dom 操作的函数上添加对应的装饰器函数

    class TodoList {
      //单例模式
      private static instance: TodoList
      private oTodoList: HTMLElement
    
      constructor(oTodoList: HTMLElement) {
        this.oTodoList = oTodoList
      }
      //创建单例的方法
      public static createInstance(oTodoList: HTMLElement) {
        if (!TodoList.instance) {
          TodoList.instance = new TodoList(oTodoList)
        }
        return TodoList.instance
      }
      /**
       * 增加的方法
       * @param todo
       * 具体步骤:创建外层容器,添加类,调用view视图层代码片段追加到创建的容器,再把容器追加到类初始化的容器中
       */
      public addItem(todo: ITodo) {
        const oItem: HTMLElement = document.createElement('div')
        oItem.className = 'todo-item'
        oItem.innerHTML = todoView(todo)
        this.oTodoList.appendChild(oItem)
      }
    
      public removeItem(id: number) {
        const oItems: HTMLCollection = document.getElementsByClassName('todo-item')
    
        Array.from(oItems).map((oItem) => {
          const _id = parseInt(oItem.querySelector('button').dataset.id)
          if (id === _id) {
            oItem.remove()
          }
        })
      }
    
      public toggleCompleted(id: number, completed?: boolean) {
        const oItems: HTMLCollection = document.getElementsByClassName('todo-item')
        Array.from(oItems).map((oItem) => {
          const _id = parseInt(oItem.querySelector('input').dataset.id)
          // const _checked = oItem.querySelector('input').checked
          if (_id === id) {
            const oContent: HTMLElement = oItem.querySelector('span')
            oContent.style.textDecoration = completed ? 'line-through' : 'none'
          }
        })
      }
    }
    

    装饰器函数:

    装饰器函数主要负责数据的操作
    通过具体的方法操作在对应的函数处理数据

    let todoData: ITodo[] = []
    
    /**
     * 添加函数的装饰器:
     * @param target 当前装饰函数的容器 xxx.prototype
     * @param methodName 被装饰的函数名称
     * @param descriptor 描述的信息,.value是被装饰执行的函数
     * 注意函数的定义,不要使用箭头函数,会改变传值
     */
    export function addTodo(
      target: any,
      methodName: string,
      descriptor: PropertyDescriptor
    ) {
      const _origin = descriptor.value
      descriptor.value = function (todo: ITodo) {
        const _todo: ITodo | null = todoData.find(
          (td: ITodo) => td.content === todo.content
        )
        if (_todo) {
          alert('该项以添加...')
          return
        }
        todoData.push(todo)
        _origin.call(this, todo)
        console.log('todoData:', todoData)
      }
    }
    
    /**
     * 删除数据装饰器:
     * @param target
     * @param methodName
     * @param descriptor
     */
    export function removeTodo(
      target: any,
      methodName: string,
      descriptor: PropertyDescriptor
    ) {
      const _origin = descriptor.value
      descriptor.value = function (id: number) {
        todoData = todoData.filter((todo: ITodo) => todo.id !== id)
        _origin.call(this, id)
        console.log('todoData:', todoData)
      }
    }
    
    /**
     * 改变选中状态
     * @param target
     * @param methodName
     * @param descriptor
     */
    export function changeCompleted(
      target: any,
      methodName: string,
      descriptor: PropertyDescriptor
    ) {
      const _origin = descriptor.value
      descriptor.value = function (id: number) {
        todoData.map((todo: ITodo) => {
          if (todo.id === id) {
            todo.completed = !todo.completed
            _origin.call(this, id, todo.completed)
          }
          return todo
        })
        console.log('changeCompleted:', todoData)
      }
    }
    
  • 相关阅读:
    JSP笔记05——生命周期(转)
    JSP笔记04——架构(转)
    JSP笔记03——环境搭建(转)
    JSP笔记02——概述(转)
    JSP笔记01——尝试
    【Head First Servlets and JSP】笔记14:session再探 & Listener示例
    【stl学习笔记】list
    【stl学习笔记】deques
    【stl学习笔记】vector
    【APUE】用户态与内核态的区别
  • 原文地址:https://www.cnblogs.com/intelwisd/p/14675032.html
Copyright © 2011-2022 走看看