js面试题,加深理解面向对象编程

831 阅读3分钟

少叨叨,先上题😎

题目一:

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

这道题可能比较简单~ 不过,看到这里,可以稍停一下,大脑里过一下思路~ 所以我把解答放在最下面😋

再来一题复杂点的~

题目二:

  • 某停车场,分3层,每层100个车位
  • 每个车位都能监控到车辆的驶入和离开
  • 车辆进入前,显示每层的空余车位数量
  • 车辆离开时,摄像头可识别车牌号和停车时间
  1. 请画出 UML 类图
  2. 用ES6语法写出该示例

这个题相对比较复杂些,仔细思考下🤔~

题目一解答:

分析题目中能抽象的类:

  • 车 - Car类,包含属性:车牌号number:String类型,车名name:String类型
  • 快车 - FastCar类,继承父类Car,包含属性:单价price:Number类型
  • 专车 - SpecialCar类,继承父类Car,包含属性:单价price:Number类型
  • 行程 - Trip类,包含属性:车car:Car类型,包含方法:行程开始start(),行程结束end()

因此UML类图如下:

JSxd0I.png

ES6 语法示例

// 行程类
class Trip {
    constructor(car) {
        this.car = car
        this.distance = 5
    }
    start() {
        console.log(`Name is ${this.car.name}, NO. is ${this.car.number}`)
    }
    end() {
        console.log(`打车金额为 ${this.car.price * this.distance}`)
    }
}
// 车类
class Car {
    constructor(name, number) {
        this.name = name
        this.number = number
    }
}
// 专车类
class SpecialCar extends Car {
    constructor(name, number) {
        super(name, number)
        this.price = 2
    }
}
// 快车类
class FastCar extends Car {
    constructor(name, number) {
        super(name, number)
        this.price = 1
    }
}

// 测试
// 初始化专车、行程数据
let car1 = new SpecialCar('special car', 's001')
let trip1 = new Trip(car1)
trip1.start()
trip1.end()
// 初始化快车、行程数据
let car2 = new FastCar('fast car', 'f001')
let trip2 = new Trip(car2)
trip2.start()
trip2.end()

/* 打印
 * Name is special car, NO. is s001
 * 打车金额为 10
 * Name is fast car, NO. is f001
 * 打车金额为 5
 */

题目二解答:

分析题目中能抽象的类:

  • 停车场 - Park类,包含属性:层floors:Array<Floor类型>,摄像头camera:Camera类型,显示屏:Screen类型,carList:Object记录车辆信息;包含方法:计算总空车位数emptyNum():Number,车辆进入in(car),车辆离开out(car)
  • 层 - Floor类,包含属性:车位数places:Array<Place类型>,层索引index:Int;包含方法:计算当前层空车位数emptyPlaceNum()
  • 车位 - Place类,包含属性:车位是否为空empty:Boolean;包含方法:车辆入位in(),车辆离位out()
  • 摄像头 - Camera类,包含方法:拍摄记录车信息shot(car):Object
  • 显示屏 - Screen类,包含方法:显示信息show(car,inTime):String
  • 车 - Car类,包含属性:车牌号number:String

因此UML类图如下:

JSxanA.png

ES6 语法示例

// 车
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(place => {
            if (place.empty) {
                num++
            }
        })
        return num
    }
}
// 车位
class Place {
    constructor() {
        this.empty = true // 车位是否为空
    }
    in() {
        this.empty = false
    }
    out() {
        this.empty = true
    }
}
// 摄像头
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} ms`) // 停车时长
    }
}

//测试
// 初始化数据
// 初始化题目中停车场的3层,每层100个车位
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('No.01')
const car2 = new Car('No.02')
const car3 = new Car('No.03')

// 模拟车辆进出
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) // 离开

/* 输出
 * 第一辆车进入
 * 1 层还有 100 个车位
 * 2 层还有 100 个车位
 * 3 层还有 100 个车位
 * 第二辆车进入
 * 1 层还有 99 个车位
 * 2 层还有 100 个车位
 * 3 层还有 100 个车位
 * 第一辆车离开
 * 车牌号 No.01
 * 停车时间 1 ms
 * 第二辆车离开
 * 车牌号 No.02
 * 停车时间 1 ms
 * 第三辆车进入
 * 1 层还有 100 个车位
 * 2 层还有 100 个车位
 * 3 层还有 100 个车位
 * 第三辆车离开
 * 车牌号 No.03
 * 停车时间 0 ms
 */

总结

代码较多,希望你看完了~ 面向对象就是面对你的对象,天天说我爱你,没有的可以new一个,哈哈哈😸~~~

万事万物皆是对象,个人理解,面向对象的这个“对象”就是把业务抽离抽象出模板/模块,像具体事物一样拥有各种属性与动作(方法),各个事物之间相互联系(耦合),具体到程序即实现继承、封装这些特性,更好的代码解耦和维护。可能理解存在偏差,希望各位多多指导。

JpQ9TP.md.png

⛽️⛽️💪