[封装01-设计模式] 设计原则 和 工厂模式(简单抽象方法)

2021-10-12  本文已影响0人  woow_wu7
design_principle设计原则.png Error.png

导航

[react] Hooks

[封装-设计模式01] 设计原则 和 工厂模式(简单抽象方法) 适配器模式 装饰器模式

[React 从零实践01-后台] 代码分割
[React 从零实践02-后台] 权限控制
[React 从零实践03-后台] 自定义hooks
[React 从零实践04-后台] docker-compose 部署react+egg+nginx+mysql
[React 从零实践05-后台] Gitlab-CI使用Docker自动化部署

[源码-webpack01-前置知识] AST抽象语法树
[源码-webpack02-前置知识] Tapable
[源码-webpack03] 手写webpack - compiler简单编译流程
[源码] Redux React-Redux01
[源码] axios
[源码] vuex
[源码-vue01] data响应式 和 初始化渲染
[源码-vue02] computed 响应式 - 初始化,访问,更新过程
[源码-vue03] watch 侦听属性 - 初始化和更新
[源码-vue04] Vue.set 和 vm.$set
[源码-vue05] Vue.extend

[源码-vue06] Vue.nextTick 和 vm.$nextTick
[部署01] Nginx
[部署02] Docker 部署vue项目
[部署03] gitlab-CI

[数据结构和算法01] 二分查找和排序

[深入01] 执行上下文
[深入02] 原型链
[深入03] 继承
[深入04] 事件循环
[深入05] 柯里化 偏函数 函数记忆
[深入06] 隐式转换 和 运算符
[深入07] 浏览器缓存机制(http缓存机制)
[深入08] 前端安全
[深入09] 深浅拷贝
[深入10] Debounce Throttle
[深入11] 前端路由
[深入12] 前端模块化
[深入13] 观察者模式 发布订阅模式 双向数据绑定
[深入14] canvas
[深入15] webSocket
[深入16] webpack
[深入17] http 和 https
[深入18] CSS-interview
[深入19] 手写Promise
[深入20] 手写函数
[深入21] 数据结构和算法 - 二分查找和排序
[深入22] js和v8垃圾回收机制
[深入23] JS设计模式 - 代理,策略,单例

[前端学java01-SpringBoot实战] 环境配置和HelloWorld服务
[前端学java02-SpringBoot实战] mybatis + mysql 实现歌曲增删改查
[前端学java03-SpringBoot实战] lombok,日志,部署
[前端学java04-SpringBoot实战] 静态资源 + 拦截器 + 前后端文件上传
[前端学java05-SpringBoot实战] 常用注解 + redis实现统计功能
[前端学java06-SpringBoot实战] 注入 + Swagger2 3.0 + 单元测试JUnit5
[前端学java07-SpringBoot实战] IOC扫描器 + 事务 + Jackson

(一) 前置知识

(1) 一些单词

principle 原则 原理
responsibility 职责 责任
substitution 代替 置换
// Single Responsibility Principle 单一职责原则

abstract 抽象的
simple 简单的
show up 出现,露面

advanced 高级的,先进的
configuration 配置
// advanced configuration 高级配置

constraint 约束
peek 偷看
shape 形状
anonymous 匿名的

(2) Error

Error.png

(二) 六大设计原则

(2.1) 单一职责原则

(2.2) 开放封闭原则

(2.3) 最少知识原则

(2.4) 里氏替换原则

(2.5) 依赖倒置原则

(2.6) 接口隔离原则

(三) 工厂模式

(3.1) 简单工厂模式

abstract class Animal {  // 抽象类不需要自己实现方法
  constructor(public name: string) {
    // this.name = name
  }
}
class Cat extends Animal { } // 继承
class Dog extends Animal { } // 继承

// 简单工厂模式
// 通过传入 (类型) 在工厂类中根据传入的类型,分别调用给构造函数去生产对应的实例
class AnimalFactory {
  static create(name: string) { // static 静态方法可以通过类本身去调用
    switch (name) { // 根据传入的类型,调用不同的构造函数,创建不同的实例
      case 'cat':
        return new Cat('cat')
      case 'dog':
        return new Dog('dog')
      default:
        return new Error('出错了')
    }
  }
}

const dog = AnimalFactory.create('dog') // 生产dog
const cat = AnimalFactory.create('cat') // 生产cat
console.log(dog)
console.log(cat)

(3.2) 工厂方法模式

abstract class Animal { // ----------------------------------------- 产品
  // 抽象类不需要自己实现方法
  constructor(public name: string) {
    // this.name = name
  }
}
class Cat extends Animal { } // ------------------------------------ 具体产品 cat
class Dog extends Animal { } // ------------------------------------ 具体产品 dog

abstract class AnimalFactory { // ---------------------------------- 具体类型的工厂抽象类
  abstract createAnimal(): Animal
}
class CatFactory extends AnimalFactory { // ------------------------ 创建cat的工厂,实现类
  // 实现类 实现 抽象类的方法
  createAnimal() {
    return new Cat('cat')
  }
}
class DogFactory extends AnimalFactory { // ------------------------ 创建dog的工厂,实现类
  // 实现类 实现 抽象类的方法
  createAnimal() {
    return new Dog('dog')
  }
}

class Factory { // ------------------------------------------------- 工厂类
  // --------------------------------------------------------------- 根据类型,让具体的工厂去生产产品
  static create(name: string) { // static 静态方法可以通过类本身去调用
    switch (name) { // 根据传入的类型,调用不同的构造函数,创建不同的实例
      case 'cat':
        return new CatFactory().createAnimal()
      case 'dog':
        return new DogFactory().createAnimal()
      default:
        return new Error('出错了')
    }
  }
}

const dog = Factory.create('dog')
const cat = Factory.create('cat')
console.log(dog)
console.log(cat)

(3.3) 抽象工厂模式

abstract class Cat {}
abstract class Dog {}
class ChinessCat extends Cat {} // 中国猫
class ChinessDog extends Dog {} // 中国狗
class EnglishCat extends Cat {} // 美国猫
class EnglishDog extends Dog {} // 美国狗

abstract class AnimalFactory { // ------------------------------- 抽象工厂类 => 抽象动物工厂
  abstract createCat(): Cat
  abstract createDog(): Dog
}

class ChineseAnimalFactory extends AnimalFactory { // ----------- 实现类 => 中国动物工厂
  createCat() {
    return new ChinessCat()
  }
  createDog() {
    return new ChinessDog()
  }
}

class EnglishAnimalFactory extends AnimalFactory { // ----------- 实现类 => 美国动物工厂
  createCat() {
    return new EnglishCat()
  }
  createDog() {
    return new EnglishDog()
  }
}

const chineseAnimal = new ChineseAnimalFactory() // ------------- 中国动物
const chineseCat = chineseAnimal.createCat() // ----------------- 中国猫
console.log(chineseCat)

(四) 适配器模式 adapter

1
// Rmb 是需要被适配的类
class Rmb {
  output() {
    return '100rmb'
  }
}

abstract class Money {
  abstract transform(): string
}

class MoneyAdaptor extends Money { // 适配器实现类
  rmb: Rmb
  constructor(rmb: Rmb) {
    super()
    this.rmb = rmb
  }
  transform() {
    return this.rmb.output() + '转成美元'
  }
}

const dollar = new MoneyAdaptor(new Rmb())
console.log(dollar.transform());
2
适配器模式在javascript中的运用 
- 概念:适配器就是将不适配东西适配起来,比如:手机转接头,转换器等
- 案例:将 ( 小写字符串 ) 适配成 ( 大写字符串 )
---

class Lower {
  getSize = () => "size";
}

class Adapter {
  lower = new Lower().getSize();
  getSize = () => this.lower.toUpperCase(); // 转成大写
}

const upper = new Adapter().getSize();

(4.1) 适配器模式有哪些运用

(4.2) 适配器模式应用案例 - axios

1. var adapter = config.adapter || defaults.adapter;

2. adapter(config).then() // 不管是什么环境,浏览器或者node都返回一个promise

3. defaultes.adapter 如下
var defaults = {
  adapter: getDefaultAdapter()
}
function getDefaultAdapter() {
  var adapter;
  if (typeof XMLHttpRequest !== 'undefined') {
    adapter = require('./adapters/xhr'); // 浏览器环境
  } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
    adapter = require('./adapters/http'); // node环境
  }
  return adapter;
}
axios({
  method: "GET",
  url: "www.baidu.com",
}).then(
  (value) => console.log(value),
  (reason) => console.error(reason)
);
// 设计模式yuanze
// 1. 单一职责原则 => 一个函数只实现一个逻辑
// 2. 开放封闭原则 => 可扩展,不可修改
// 3. 最少知识原则 => 模块,函数,方法,变量都要尽量依赖其他类和对象
// 4. 里氏替换原则 => 基类可以用子类直接替换
// 5. 接口隔离原则
// 6. 依赖倒置原则 => 实现类 依赖 接口或者抽象类

// 浏览器端
function xhrAdaptor(config) {
  const { method, url } = config;
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open(method, url, true);
    xhr.setRequestHeader("Content-Type", "application/json"); // setRequestHeader 必须是在 open之后 send之前
    xhr.responseType = "json";
    xhr.onreadystatechange = function () {
      if (xhr.readyState !== 4) {
        return;
        // readyState
        // 0 UNSENT ------------- xhr实例已经被创建,open()方法未被调用
        // 1 OPEND -------------- open()方法被调用,send()方法未被调用,setRequestHeader() 可以被调用
        // 2 HEADERS_RECEIVED --- send()方法被调用,响应头和响应状态已经返回
        // 3 LOADING ------------ 响应体(response entity body)正在下载中,此状态下通过 xhr.response 可能已经有了响应数据
        // 4 DONE --------------- 整个数据传输过程已经完成,无论本次请求是成功还是失败
      }
      if (xhr.status === 200) {
        // readyState === 4 && status === 200
        return resolve(xhr.responseText);
      } else {
        return reject(new Error(xhr.statusText));
      }
    };
    xhr.onerror = function () {
      console.error("error");
    };
    // xhr.onload = function() {
    //     if (xhr.status > 200 && xhr.status < 300 || xhr.status === 304) {
    //         return resolve(xhr.responseText)
    //     }
    // }
    xhr.send();
  });
}

// 服务器端
function httpAdaptor(config) {
  const { method, url } = config
  const http = requrie('http')
  const {hostname, port, path} = url.parse(url)
  return new Promise((resolve, reject) => {
    // http模块
    const options = {
      method,
      hostname,
      port,
      path
    };
    let req = http.request(options, function (response) {
      let chunks = [];
      response.on("data", function (chunk) {
        chunks.push(chunk);
      });
      response.on("end", function () {
        const result = Buffer.concat(chunks).toString();
        return resolve(result);
      });
    });
    req.on("error", function (error) {
      return reject(error);
    });
  });
}


function getDefaultAdaptor() {
  // ---------------------- 适配器模式,根据环境调用不同的方法
  let adaptor;
  if (typeof XMLHttpRequest !== "undefined") {
    // ------ 浏览器环境
    adaptor = xhrAdaptor;
  }
  if (typeof process !== "undefined") {
    // ------------- node环境
    adaptor = httpAdaptor;
  }
  return adaptor;
}

function axios(config) {
  const adaptor = getDefaultAdaptor();
  return adaptor(config);
  // axios返回值就是一个promise对象,无论是浏览器端还是node端
}

(五) 装饰器模式

abstract class Shape { // 形状抽象类
  abstract draw(): void;
}

class Circle extends Shape { // 形状子类 圆
  draw() {
    console.log("绘制圆");
  }
}

class Rectagle extends Shape { // 形状子类 矩形
  draw() {
    console.log("绘制矩形");
  }
}

abstract class Color extends Shape { // Color 也继承 Shape
  constructor(public shape: Shape) {
    super();
  }
  abstract draw(): void;
}

class Red extends Color {
  draw() {
    this.shape.draw(); // 调用传入的参数实例的draw方法,在new Red()时传入的参数是new Circle()
    console.log("绘制红色");
  }
}
class Yellow extends Color {
  draw() {
    this.shape.draw();
    console.log("绘制黄色");
  }
}

const redCircle = new Red(new Circle());
redCircle.draw() // 调用实例上的draw方法
image.png

(5.1) 装饰器模式在前端中的运用

/**
 * 借助装饰者模式,很容易衍生出 AOP 面向切面编程的概念
 * - 场景:典型场景就是对表单的验证,我们将把表单输入逻辑校验的 validata 函数融入到 before 逻辑当中
 * - 具体:
 *   1. 在提交表单时,执行 ( submit ) 函数,因为在 ( Function.prototype.before ) 挂载了 ( before ) 函数,被所有实例函数所继承
 *   2. 我们并不直接submit函数,而是调用 ( submit.before ) 从而在 sumbit 之前执行验证函数 ( validate ) 从而在执行sumbit之前做表单验证功能
 */
Function.prototype.before = function(beforefn) {
  const self = this
  return function() {
    if (beforefn.apply(this, arguments) === false) return // 表示执行验证逻辑时,验证未通过
    return self.apply(this, arguments) // this是调用before方法时所在的对象,是 submitBtn 在调用before,所以在了的 self 就是 submitBtn 函数
  }
}

const validate = function() {
  // 表单验证逻辑
}

const formSubmit = function() {
  // 表达提交逻辑
  ajax('http:// xxx.com/login', param)
}

submitBtn.onclick = function() {
  formSubmit.before(validate)
}

资料

设计原则1 https://juejin.cn/post/6844904025565970439
设计原则2 https://juejin.cn/post/6847902225717854215
装饰器模式1 https://juejin.cn/post/6914235611545092109
装饰器模式2 https://juejin.cn/post/6881897639001751560

vscode=>codeRunner=>ts-node出现乱码解决方案如下
https://github.com/formulahendry/vscode-code-runner/issues/632

上一篇 下一篇

猜你喜欢

热点阅读