面试题答案
一键面试1. 重构继承链
1.1 提取公共部分为混合类(Mixin)
继承链冗长可能是因为多个子类重复继承了一些通用功能。可以将这些通用功能提取出来,通过混合类的方式复用。
// 定义一个通用功能的混合类
type Constructor<T = {}> = new (...args: any[]) => T;
function Loggable<TBase extends Constructor>(Base: TBase) {
return class extends Base {
log(message: string) {
console.log(`${this.constructor.name}: ${message}`);
}
};
}
class Animal {
constructor(public name: string) {}
}
// 使用混合类扩展Animal类
class Dog extends Loggable(Animal) {
bark() {
this.log('Woof!');
}
}
const dog = new Dog('Buddy');
dog.bark(); // 输出: Dog: Woof!
1.2 组合代替继承
过多的继承可以通过组合的方式简化。例如,如果一个类继承了多个父类的功能,可以将这些功能作为成员变量引入。
class Flyable {
fly() {
console.log('I can fly');
}
}
class Swimmable {
swim() {
console.log('I can swim');
}
}
class Duck {
private flyable: Flyable;
private swimmable: Swimmable;
constructor() {
this.flyable = new Flyable();
this.swimmable = new Swimmable();
}
performActions() {
this.flyable.fly();
this.swimmable.swim();
}
}
const duck = new Duck();
duck.performActions();
// 输出:
// I can fly
// I can swim
2. 优化多态性实现方式
2.1 使用函数重载优化多态
在一些情况下,函数重载可以提供更清晰和高效的多态实现。
function printValue(value: string): void;
function printValue(value: number): void;
function printValue(value: any) {
if (typeof value ==='string') {
console.log(`String: ${value}`);
} else if (typeof value === 'number') {
console.log(`Number: ${value}`);
}
}
printValue('Hello'); // 输出: String: Hello
printValue(42); // 输出: Number: 42
2.2 基于类型判断的多态
利用TypeScript的类型断言和类型保护进行更灵活的多态。
class Shape {
draw() {
console.log('Drawing a shape');
}
}
class Circle extends Shape {
draw() {
console.log('Drawing a circle');
}
}
class Square extends Shape {
draw() {
console.log('Drawing a square');
}
}
function drawShapes(shapes: Shape[]) {
shapes.forEach(shape => {
if (shape instanceof Circle) {
shape.draw();
} else if (shape instanceof Square) {
shape.draw();
} else {
shape.draw();
}
});
}
const shapes: Shape[] = [new Circle(), new Square()];
drawShapes(shapes);
// 输出:
// Drawing a circle
// Drawing a square
3. 设计模式的应用
3.1 策略模式
当多态性导致性能问题时,策略模式可以将不同的行为封装成独立的策略类。
interface SortStrategy {
sort(arr: number[]): number[];
}
class QuickSortStrategy implements SortStrategy {
sort(arr: number[]): number[] {
if (arr.length <= 1) {
return arr;
}
const pivot = arr[Math.floor(arr.length / 2)];
const left = [];
const right = [];
const equal = [];
for (const num of arr) {
if (num < pivot) {
left.push(num);
} else if (num > pivot) {
right.push(num);
} else {
equal.push(num);
}
}
return [...this.sort(left), ...equal, ...this.sort(right)];
}
}
class MergeSortStrategy implements SortStrategy {
sort(arr: number[]): number[] {
if (arr.length <= 1) {
return arr;
}
const mid = Math.floor(arr.length / 2);
const left = arr.slice(0, mid);
const right = arr.slice(mid);
return this.merge(this.sort(left), this.sort(right));
}
merge(left: number[], right: number[]): number[] {
let result: number[] = [];
let i = 0;
let j = 0;
while (i < left.length && j < right.length) {
if (left[i] < right[j]) {
result.push(left[i]);
i++;
} else {
result.push(right[j]);
j++;
}
}
return result.concat(left.slice(i)).concat(right.slice(j));
}
}
class Sorter {
private strategy: SortStrategy;
constructor(strategy: SortStrategy) {
this.strategy = strategy;
}
setStrategy(strategy: SortStrategy) {
this.strategy = strategy;
}
sortArray(arr: number[]): number[] {
return this.strategy.sort(arr);
}
}
const sorter = new Sorter(new QuickSortStrategy());
const numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];
console.log(sorter.sortArray(numbers));
// 输出: [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
sorter.setStrategy(new MergeSortStrategy());
console.log(sorter.sortArray(numbers));
// 输出: [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
3.2 装饰器模式
用于在运行时给对象添加新的功能,而不是通过继承来扩展类。
// 定义一个装饰器函数
function Logger(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling ${propertyKey} with args:`, args);
const result = originalMethod.apply(this, args);
console.log(`${propertyKey} returned:`, result);
return result;
};
return descriptor;
}
class MathOperations {
@Logger
add(a: number, b: number) {
return a + b;
}
}
const mathOps = new MathOperations();
mathOps.add(2, 3);
// 输出:
// Calling add with args: [2, 3]
// add returned: 5