设计原则、设计模式

面向对象

三要素继承(子类继承父类)、封装(数据的权限和保密)、多态(同一接口不同实现)

封装public 完全开放  protected 对子类开放  private 对自己开放

封装特性: 减少耦合,不该外露的不外露;利于数据、接口的权限管理;以_开头的属性是私有的

多态特性: 保持子类的开放性、灵活性,面向接口编程

为什么要面向对象编程?

程序执行机制:顺序 —— 判断—— 循环  (结构化)

面向对象 —— 数据结构化

对于计算机,结构化的才是最简单的

编程应该简单抽象

UML类图

unified modeling language 统一建模语言

设计原则

《UNIX/LINUX设计哲学》

设计准则:

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

小准则:

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

SOLID五大设计原则

S:单一职责原则

一个程序只做好一件事

如果功能过于复杂就拆开,各部分保持独立

O:开放封闭原则

对扩展开放、对修改封闭

增加需求时,扩展新代码,而非修改已有代码

软件设计的终极目标

L:李氏置换原则

子类能覆盖父类

父类能出现的地方子类就能出现

I:接口独立原则

保持接口的单一独立,避免出现胖接口

D:依赖倒置原则

面向接口编程,依赖于抽象而不依赖于具体

使用方法只关注接口而不关注具体类的实现

从设计到模式

面试题

1、打时,可以打专车或者快车,任何车都有车牌号和名称;不同车价格不同,快车每公里1元专车每公里2元行程开始时,显示车辆信息;行程结束时,显示打车金额

  (1) 画出UML类图

(2)用 es6 语法写出该示例

class Car {
    constructor(number, name) {
        this.number = number
        this.name = name
    }
}
class Kuaiche extends Car {
    constructor(number, name) {
        super(number, name)
        this.price = 1
    }
}
class Zhuanche extends Car {
    constructor(number, name) {
        super(number, name)
        this.price = 2
    }
}

class Trip {
    constructor(car) {
        this.car = car
    }
    start() {
        console.log(`行程开始,名称: ${this.car.name}, 车牌号: ${this.car.price}`)
    }
    end() {
        console.log('行程结束,价格: ' + (this.car.price * 5))
    }
}

let car = new Kuaiche(100, '桑塔纳')
let trip = new Trip(car)
trip.start()
trip.end()

2、某停车场,分3层,每层100车位;每个车位都能监控到车辆的驶入和离开;车辆进入前,显示每层的空余车位数量;车辆进入时,摄像头可以识别车牌号和时间;车辆出来时,出口显示器显示 车牌号和停车时长

       (1)画出UML类图

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

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

// 出口显示器
class Screen {
    show(car, inTime) {
        console.log('车牌号', car.num)
        console.log('停车时间', Date.now() - inTime)
    }
}

// 停车场
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() {
        this.empty = true
    }
    in() {
        this.empty = false
    }
    out() {
        this.empty = true
    }
}

// 测试代码------------------------------
// 初始化停车场
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('A1')
const car2 = new Car('A2')
const car3 = new Car('A3')

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)

设计模式

工厂模式(构造函数和创建者分离)

// 工厂函数
export default function (list, itemData) {
    if (itemData.discount) {
        itemData = createDiscount(itemData)
    }
    return new Item(list, itemData)
}

单例模式(系统中被唯一使用,一个类只有一个实例)

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

适配器模式(封装旧接口)

var $ = {
    ajax: function(options) {
        return ajax(options)
    }
}

装饰器模式(将现有对象和装饰器进行分离,两者独立存在)

function log(target, name, descriptor) {
  var oldValue = descriptor.value;

  descriptor.value = function() {
    console.log(`Calling ${name} with`, arguments);
    return oldValue.apply(this, arguments);
  };

  return descriptor;
}

class Math {
  @log
  add(a, b) {
    return a + b;
  }
}

代理模式(代理类和目标类分离,隔离开目标类和使用者)

// 明星
let star = {
    name: '张XX',
    age: 25,
    phone: '13910733521'
}

// 经纪人
let agent = new Proxy(star, {
    get: function (target, key) {
        if (key === 'phone') {
            // 返回经纪人自己的手机号
            return '18611112222'
        }
        if (key === 'price') {
            // 明星不报价,经纪人报价
            return 120000
        }
        return target[key]
    },
    set: function (target, key, val) {
        if (key === 'customPrice') {
            if (val < 100000) {
                // 最低 10w
                throw new Error('价格太低')
            } else {
                target[key] = val
                return true
            }
        }
    }
})

外观模式(为子系统中的一组接口提供一个高层接口,使用高层接口)

观察者模式(主题和观察者分离,两者解耦)

使用场景

  • 网页事件绑定
  • promise
  • jQuery callbacks
  • nodejs 自定义事件
// 主题,接收状态变化,触发每个观察者
class Subject {
    constructor() {
        this.state = 0
        this.observers = []
    }
    getState() {
        return this.state
    }
    setState(state) {
        this.state = state
        this.notifyAllObservers()
    }
    attach(observer) {
        this.observers.push(observer)
    }
    notifyAllObservers() {
        this.observers.forEach(observer => {
            observer.update()
        })
    }
}

// 观察者,等待被触发
class Observer {
    constructor(name, subject) {
        this.name = name
        this.subject = subject
        this.subject.attach(this)
    }
    update() {
        console.log(`${this.name} update, state: ${this.subject.getState()}`)
    }
}

迭代器模式(顺序访问一个集合,无需知道内部结构)

class Iterator {
    constructor(conatiner) {
        this.list = conatiner.list
        this.index = 0
    }
    next() {
        if (this.hasNext()) {
            return this.list[this.index++]
        }
        return null
    }
    hasNext() {
        if (this.index >= this.list.length) {
            return false
        }
        return true
    }
}

class Container {
    constructor(list) {
        this.list = list
    }
    getIterator() {
        return new Iterator(this)
    }
}

// 测试代码
let container = new Container([1, 2, 3, 4, 5])
let iterator = container.getIterator()
while(iterator.hasNext()) {
    console.log(iterator.next())
}

状态模式(将状态对象和主题对象分离,状态的变化逻辑单独处理)

class State {
    constructor(color) {
        this.color = color
    }
    handle(context) {
        console.log(`turn to ${this.color} light`)
        context.setState(this)
    }
}

class Context {
    constructor() {
        this.state = null
    }
    setState(state) {
        this.state = state
    }
    getState() {
        return this.state
    }
}

// 测试代码
let context = new Context()

let greed = new State('greed')
let yellow = new State('yellow')
let red = new State('red')

// 绿灯亮了
greed.handle(context)
console.log(context.getState())
// 黄灯亮了
yellow.handle(context)
console.log(context.getState())
// 红灯亮了
red.handle(context)
console.log(context.getState())

其他设计模式

原型模式(clone自己, 生成一个新对象)

桥接模式(把抽象化和现实化解耦,使二者独立变化)

组合模式(生成树形结构,表示“整体——部分”的关系,一致的操作方式)

享元模式(共享内存,相同数据、共同使用)

策略模式(不同策略分开处理)

模板方法模式

职责链模式(一步操作分为多个职责,角色分开链串起来)

命令模式(执行命令时,发布者和执行者分开,中间加入命令对象,作为中转站)

备忘录模式(随时记录一个对象的状态变化,随时恢复之前的某个状态)

中介者模式(将各关联对象通过中介者隔离)

访问者模式(将数据操作和数据结构进行分离)

解释器模式(描述语言语法如何定义,如何解释和编译)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值