【12】设计模式实战演练

01-面试题 - 打车

题目

背景

  • 打车时,你可以打快车和专车
  • 无论什么车,都有车牌号和车辆名称
  • 打不同的车价格不同,快车每公里 1 元,专车每公里 2 元
  • 打车时,你要启动行程并显示车辆信息
  • 结束行程,显示价格(假定行驶了 5 公里)

题目

  • 画出 UML 类图
  • 用 TS 语法写出该示例

分析

抽象数据模型

  • 车,抽象为一个 class
  • 快车,专车是派生类,有一个父类或接口 (快车、专车,有相同,有不同)
  • 行程,抽象为一个 class ,且和车有关系

属性和方法

  • 车:车牌号,名称(在父类或接口),价格(在派生类)
  • 行程:开始,结束
  • 行程:关联的车辆

UML 类图

在这里插入图片描述

代码演示

class Car {
    name: string
    number: string
    price = 0
    constructor(name: string, number: string) {
        this.name = name
        this.number = number
    }
}

class ExpressCar extends Car {
    price = 1
    constructor(name: string, number: string) {
        super(name, number)
    }
}

class SpecialCar extends Car {
    price = 2
    constructor(name: string, number: string) {
        super(name, number)
    }
}

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

// const car = new ExpressCar('桑塔纳', 'A111222')
const car = new SpecialCar('迈腾', 'B333444')
const trip = new Trip(car)
trip.start()
trip.end()

总结

  • 分析:数据模型,属性和方法,关系
  • UML 类图
  • 代码演示

02-面试题 - 停车场

题目

描述:

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

题目:

  • 画出 UML 类图

(代码量较多,正式面试时不用一行一行写,画图即可)

分析

数据模型

  • 停车场,层,车位
  • 摄像头,显示屏

梳理流程

  • 进入之前:显示当前空余车位
  • 进入:计停车数量,计算开始时间
  • 离开:计算结束时间,减停车数量

UML 类图

在这里插入图片描述

代码演示

HTML 代码

<div>
    <button id="btn-car1-into">car1 进入</button>
    <button id="btn-car1-out">car1 离开</button>
    <br>
    <button id="btn-car2-into">car2 进入</button>
    <button id="btn-car2-out">car2 离开</button>
    <br>
    <button id="btn-car3-into">car3 进入</button>
    <button id="btn-car3-out">car3 离开</button>
</div>

TS 代码

// 车
class Car {
    number: string
    constructor(number: string) {
        this.number = number
    }
}

// 停车信息
interface IEntryInfo {
    number: string
    inTime: number
    place?: ParkPlace
}

// 入口摄像头
class ParkCamera {
    // 拍照
    shot(car: Car): IEntryInfo {
        return {
            number: car.number,
            inTime: Date.now()
        }
    }
}

// 出口显示器
class ParkScreen {
    show(info: IEntryInfo) {
        const { inTime, number } = info
        const duration = Date.now() - inTime
        console.log(`车牌号:${number} ,停留时间:${duration}`)
    }
}

// 车位
class ParkPlace {
    isEmpty = true
    getInto() {
        this.isEmpty = false
    }
    out() {
        this.isEmpty = true
    }
}

// 层
class ParkFloor {
    index: number
    parkPlaces: ParkPlace[]
    constructor(index: number, places: ParkPlace[]) {
        this.index = index
        this.parkPlaces = places
    }
    get emptyPlaceNum(): number {
        let num = 0
        for (const place of this.parkPlaces) {
            if (place.isEmpty) num++
        }
        return num
    }
}

// 停车场
class Park {
    parkFloors: ParkFloor[]
    parkCamera = new ParkCamera()
    parkScreen = new ParkScreen()
    entryInfoList: Map<string, IEntryInfo> = new Map() // key 是 car.number

    constructor(floors: ParkFloor[]) {
        this.parkFloors = floors
    }

    getInto(car: Car) {
        // 获取摄像头的信息:车牌号,时间
        const entryInfo = this.parkCamera.shot(car)
        // 某个车位
        const i = Math.round((Math.random() * 100) % 100)
        const place = this.parkFloors[0].parkPlaces[i] // 停在第一层的某个车位(想要第二层,第三层,也可以用随机数获取)
        // 进入车位
        place.getInto()
        // 记录停车信息
        entryInfo.place = place
        this.entryInfoList.set(car.number, entryInfo)
    }

    out(car: Car) {
        // 获取停车信息
        const entryInfo = this.entryInfoList.get(car.number)
        if (entryInfo == null) return
        const { place } = entryInfo
        if (place == null) return

        // 从车位离开
        place.out()

        // 出口显示屏,显示
        this.parkScreen.show(entryInfo)

        // 删除停车信息
        this.entryInfoList.delete(car.number)
    }

    // 当前停车场的空余车位
    get emptyInfo(): string {
        return this.parkFloors.map(floor => {
            return `${floor.index} 层还有 ${floor.emptyPlaceNum} 个车位`
        }).join('\n')
    }
}

// ---------- 初始化停车场 ----------
const floors: ParkFloor[] = []
// 3 层
for (let i = 0; i < 3; i++) {
    const places: ParkPlace[] = []
    // 每层 100 个车位
    for (let j = 0; j < 100; j++) {
        places[j] = new ParkPlace()
    }
    floors[i] = new ParkFloor(i + 1, places)
}
const park = new Park(floors)

// ---------- 模拟车辆进入、离开 ----------
const car1 = new Car('A1')
const car2 = new Car('A2')
const car3 = new Car('A3')

document.getElementById('btn-car1-into')?.addEventListener('click', () => {
    console.log('第一辆车即将进入')
    console.log(park.emptyInfo)
    park.getInto(car1)
})
document.getElementById('btn-car1-out')?.addEventListener('click', () => {
    console.log('第一辆车离开')
    park.out(car1)
})
document.getElementById('btn-car2-into')?.addEventListener('click', () => {
    console.log('第二辆车即将进入')
    console.log(park.emptyInfo)
    park.getInto(car2)
})
document.getElementById('btn-car2-out')?.addEventListener('click', () => {
    console.log('第二辆车离开')
    park.out(car2)
})
document.getElementById('btn-car3-into')?.addEventListener('click', () => {
    console.log('第三辆车即将进入')
    console.log(park.emptyInfo)
    park.getInto(car3)
})
document.getElementById('btn-car3-out')?.addEventListener('click', () => {
    console.log('第三辆车离开')
    park.out(car3)
})

总结

  • 题目信息
  • 分析
  • UML 类图
  • 代码演示

03-总结

内容回顾

  • 面试题 - 模拟打车
  • 面试题 - 模拟停车场

注意事项

  • 先审题、分析,切忌一开始就写代码
  • 关注整体设计,别较真细节

如果面试遇到设计相关的问题,你应该如何思考,分几个步骤?

思考方式很重要,课程里也重点强调过了。

如果思考方式不对,将会事倍功半,特别是在面试这样一个时间紧张的环境下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值