前端设计模式之面试实战(十一)
面试题 - 打车
背景
- 打车时,你可以打快车和专车(都有车辆名称和车牌号)
- 快车每公里 1 元,专车每公里 2 元
- 打车时,你要启动行程并显示车辆信息
- 结束行程,显示价格(假定行驶了 5 公里)
分析
抽象数据模型
-
车,抽象为一个 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(); // 行程开始,名称: 迈腾, 车牌号: B333444
trip.end(); // 行程结束,价格: 10
面试题 - 停车场
背景
- 某停车场,分 3 层,每层 100 车位
- 每个车位可以监控车辆的进入和离开
- 车辆进入前,显示每层的空余车位数量
- 车辆进入时,摄像头可识别车牌号和时间
- 车辆出来时,出口显示器显示车牌号和停车时长
分析
数据模型
-
车
-
停车场,层,车位
-
摄像头,显示屏
梳理流程
- 进入之前:显示当前空余车位
- 进入:计停车数量,计算开始时间
- 离开:计算结束时间,减停车数量
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);
});
总结专栏内容:
转载自:https://juejin.cn/post/7198154204538994725