JS设计原则

1. 何为设计?

设计即按照哪一种思路或者标准来实现功能
功能相同,可以有不同设计方案来实现
伴随着需求增加,设计到作用才能体现出来

《UNIX / LINUX 设计哲学》

准则1:小即是美
准则2:让每个程序只做好一件事
准则3:快速建立原型
准则4:舍弃高效率而取可移植性
准则5:采用纯文本来存储数据
准则6:充分利用软件的杠杆效应(软件复用)
准则7:使用shell脚本来提高杠杆效应和可移植性
准则8:避免强制性的用户界面
准则9:让每个程序都称为过滤器

《UNIX / LINUX 设计哲学》 - 小准则

允许用户定制环境
尽量使操作系统内核小而轻量化
使用小写字母并尽量简短
沉默是金
各部分只和大于整体
寻求90%的解决方案

2. 五大设计原则(SOLID)?

  • S - single 单一职责原则
  • O - open 开放封闭原则(对扩展开放,对修改封闭)
  • L - Liskov 里氏置换原则
  • I - interface 接口独立原则
  • D - dependency 依赖倒置原则

(1)S - 单一职责原则

  • 一个程序只做好一件事
  • 如果功能过于复杂就拆分开,每个部分保持独立

(2) O - 开放封闭原则

  • 对扩展开放,对修改封闭
  • 增加需求时,扩展新代码,而非修改已有代码
  • 这是软件设计的终极目标

(3) L - 里氏置换原则

  • 子类能覆盖父类
  • 父类能出现的地方子类就能出现
  • JS中使用较少(弱类型 & 继承使用较少)

(4) I - 接口独立原则

  • 保持接口的单一独立,避免出现“胖接口”
  • JS中没有接口(typescript例外),使用较少
  • 类似于单一职责原则,这里更关注接口

(5)D - 依赖倒置原则

  • 面向接口编程,依赖于抽象而不依赖于具体
  • 使用方只关注接口而不关注具体类的实现
  • JS中使用较少(没有接口 & 弱类型)

用Promise来说明SO

  • 单一职责原则:每个then中的逻辑只做好一件事
  • 开放封闭原则:如果新增需求,扩展then
  • 对扩展开放、对修改封闭

3. 23种设计模式

(1)创建型

  • 工厂模式(工厂方法模式,抽象工厂模式,建造者模式)
  • 单例模式
  • 原型模式

(2)结构型

  • 适配器模式
  • 装饰器模式
  • 代理模式
  • 外观模式
  • 桥接模式
  • 组合模式
  • 享元模式

(3)行为型

  • 策略模式
  • 模板方法模式
  • 观察者模式
  • 迭代器模式
  • 职责连模式
  • 命令模式
  • 备忘录模式
  • 状态模式
  • 访问者模式
  • 中介者模式
  • 解释器模式

4. 设计原则面试题

(1)打车时,可以打专车或者快车,任何车都有车牌号和名称。不同车价格不同,快车每公里1元,专车每公里2元。行程开始时,显示车辆信息。行程结束时,显示打车金额(假定行程就5公里)。画出UML类图,用ES6语法写出该示例
在这里插入图片描述

	class Car{
   
       constructor(num, name){
   
         this.num = num
         this.name = name
       }
     }
     class Trip{
   
       constructor(car){
   
         this.car = Car
       }
       start(){
   
         console.log(`车辆信息:车牌号为${
     this.car.num},名称为${
     this.car.name}`)
       }
       end(){
   
         console.log(`价格:${
     this.car.amount * 5}`)
       }
     }
     class Kuai extends Car{
   
       constructor(num, name){
   
         super(num, name)
         this.amount = 1
       }
     }
     class Zhuan extends Car{
   
       constructor(num, name){
   
         super(num, name)
         this.amount = 2
       }
     }

     var kuai = new Kuai(123, '快车')
     let trip = new Trip(kuai)
     trip.start()
     trip.end()

(2)某停车场,分3层,每层100车位。每个车位都能监控到车辆的驶入和离开,车辆进入前,显示每层的空余车位数量。车辆进入时,摄像头可识别车牌号和时间,车辆出来时,出口显示器显示车牌号和停车时长。画出UML类图。
在这里插入图片描述

	// 车辆
    class Car{
   
      constructor(num){
   
        this.num = num
      }
    }

    // 停车场
    class Park{
   
      constructor(floors){
   
        this.floors = floors || []
        this.camera = new Camera()
        this.screen = new Screen()
        this.carList = {
   }  // 存储摄像头拍摄返回的车辆信息
      }
      in(car){
   
        // 通过摄像头获取信息
        const info = this.camera.shot(car)

        // 停到某个停车位
        const i = parseInt(Math.random() * 100 % 100)
        const place = this.floors[0].places[i]
        place.in()
        info.place = place

        // 记录信息
        this.carList[car.num] = info
      }
      out(car){
   
        // 获取信息
        const info = this.carList[car.num]

        // 将车位清空
        const place = info.place
        place.out()

        // 显示时间
        this.screen.show(car, info.inTime)

        // 清空记录
        delete this.carList[car.num]
      }
      emptyNum(){
   
        return this.floors.map(floor => {
   
          return `${
     floor.index} 层还有${
     floor.emptyPlaceNum()}个空闲车位}`
        }).join('\n')
      }
    }

    // 层
    class Floor{
   
      constructor(index, places){
   
        this.index = index
        this.places = places || []
      }
      emptyPlaceNum(){
   
        let num = 0
        this.places.forEach(p => {
   
          if(p.empty){
   
            num = num + 1
          }
        })
        return num
      }
    }

    // 停车位
    class Place{
   
      constructor(empty){
   
        this.empty = true
      }
      in(){
   
        this.empty = false
      }
      out(){
   
        this.empty = true
      }
    }

    // 屏幕
    class Screen{
   
      show(car, inTime){
   
        console.log('车牌号', car.num)
        console.log('停车时间', Date.now() - inTime)
      }
    }


    // 摄像机
    class Camera{
   
      shot(car){
   
        return {
   
          num: car.num,
          inTime: Date.now()
        }
      }
    }

    // 初始化停车场
    const floors = []
    for(let i = 0; i < 3; i++){
   
      const places = []
      for(let j = 0; j < 100; j++){
   
        places[j] = new Place()
      }
      floors[i] = new Floor(i + 1, places)
    }
    const park = new Park(floors)

    // 初始化车辆
    const car1 = new Car(100)
    const car2 = new Car(200)
    const car3 = new Car(300)

    console.log('第一辆车进入')
    console.log(park.emptyNum())
    park.in(car1)
    console.log('第二辆车进入')
    console.log(park.emptyNum())
    park.in(car2)
    console.log('第一辆车离开')
    park.out(car1)
    console.log('第二辆车离开')
    park.out(car2)
    console.log('第三辆车进入')
    console.log(park.emptyNum())
    park.in(car3)
    console.log('第三辆车离开')
    park.out(car3)

5. 工厂模式

  • 将new操作单独封装
  • 遇到new时,就要考虑是否该使用工厂模式

(1)使用场景:

  • jQuery - $(‘div’)
  • React.createElement
  • vue异步组件

(2)设计原则验证

  • 构造函数和创建者分离
  • 符合开放封闭原则

6. 单例模式

  • 系统中被唯一使用
  • 一个类只有一个实例

(1)使用场景:

  • 登录框
  • 购物车

(2)说明:

  • 单例模式需要用到java的特性(private)
  • ES6中没有(typescript除外)

(3)JS使用单例模式

class SingleObject{
   
	login(){
   
		console.log('login...')
	}
}
SingleObject.getInstance = (function(){
   
	let instance
	return function(){
   
		if(!instance){
   
			instance = new SingleObject();
		}
		return instance
	}
})()

// 测试
let obj1 = SingleObject.getInstance()
obj1.login()
let obj2 = SingleObject.getInstance()
obj2.login()

console.log('obj1 === obj2', obj1 === obj2)  // true

let obj3 = new SingleObject()
obj3.login()
console.log('obj1 === obj3', obj1 === obj3)  // false

(4)场景

  • jQuery只有一个$
  • 模拟登录框
  • vuex和redux中的store

(5)设计原则验证

  • 符合单一职责原则,只实例化唯一的对象
  • 没法具体体现开放封闭原则,但是绝对不违反开放封闭原则

7. 适配器模式

  • 旧接口格式和使用者不兼容
  • 中间加一个适配转换接口

在这里插入图片描述

class Adaptee(){
   
	specificRequest(){
   
		return '德国标准插头'
	}
}
class Target{
   
	constructor(){
   
		this.adaptee = new Adaptee()
	}
	request(){
   
		let info = this.adaptee.specificRequest()
		return `${
     info} - 转换器 - 中国标准插头`
	}
}

// 测试
let target = new Target()
let res = target.request()
console.log(res)

(1)场景

  • 封装旧接口
// 自己封装的ajax,使用方式如下:
ajax({
   
	url: 'getData',
	type: 'Post',
	dataType: 'json',
	data: {
   
		id: '123'
	}
})
.done(function(){
   })

// 但因为历史原因,代码中全都是:$.ajax({...})
// 做一层适配器
var $ = {
   
	ajax: function(options){
   
		return ajax(options)
	}
}
  • vue computed
<div id='example'>
	<p>Original message: {
  {message}}</p>
	<p>Computed reversed message: {
  {reversedMessage}}</p>
</div>
var vm = new Vue({
   
	el: 'example',
	data: {
   
		message: 'Hello',
	},
	computed: {
   
		// 计算属性的 getter
		reversedMessage: function(){
   
			// 'this' 指向vm实例
			return this.message.split('').reverse().join('')
		}
	}
})

(2)设计原则验证

  • 将旧接口和使用者进行分离
  • 符合开放封闭原则

8. 装饰器模式

  • 为对象添加新功能
  • 不改变其原有的结构和功能
    在这里插入图片描述
class Circle{
   
	draw(){
   
		console.log('画一个圆形')
	}
}
class Decorator{
   
	constructor(circle){
   
		this.circle = circle
		this.setRedBorder(circle)
	}
	setRedBorder(circle){
   
		console.log('设置红色边框')
	}
}

// 测试
let circle = new Circle()
circle.draw()

let dec = new Decorator(circle)
dec.draw<
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值