面试题答案
一键面试选择组合设计模式
- 代码维护性:
- 继承:继承会导致类之间紧密耦合。如果基类发生变化,所有子类可能受到影响,需要大量修改代码。例如,若商品基类添加一个新属性,所有继承自它的实体商品类和虚拟商品类等都要重新审视和调整。
- 组合:组合将不同功能封装在各自独立的类中,通过组合关系将这些类组合在一起。当某个功能需要修改时,只需要修改对应的类,不会影响其他无关类,代码维护更加容易。
- 扩展性:
- 继承:在增加新的商品类型时,需要创建新的子类,若继承体系复杂,新子类的创建可能需要考虑多重继承关系等复杂情况,扩展性受限。
- 组合:可以轻松添加新的功能类,并通过组合方式将其添加到商品类中,而不需要修改现有类的继承结构,扩展性强。
- 性能:
- 继承:在继承体系较深时,可能存在内存浪费和性能开销,因为子类可能继承了一些不需要的属性和方法。
- 组合:按需组合所需功能,不会产生不必要的继承开销,性能更好。
TypeScript代码示例
// 定义实体商品的属性和行为类
class PhysicalProductDetails {
weight: number;
constructor(weight: number) {
this.weight = weight;
}
getWeight() {
return this.weight;
}
}
// 定义虚拟商品的属性和行为类
class DigitalProductDetails {
fileSize: number;
constructor(fileSize: number) {
this.fileSize = fileSize;
}
getFileSize() {
return this.fileSize;
}
}
// 商品基类,使用组合方式
class Product {
name: string;
price: number;
private details: PhysicalProductDetails | DigitalProductDetails | null;
constructor(name: string, price: number) {
this.name = name;
this.price = price;
this.details = null;
}
setPhysicalDetails(weight: number) {
this.details = new PhysicalProductDetails(weight);
}
setDigitalDetails(fileSize: number) {
this.details = new DigitalProductDetails(fileSize);
}
getDetails() {
return this.details;
}
}
// 使用示例
let physicalProduct = new Product('Book', 20);
physicalProduct.setPhysicalDetails(0.5);
console.log(physicalProduct.getDetails()?.getWeight());
let digitalProduct = new Product('E - book', 15);
digitalProduct.setDigitalDetails(5);
console.log(digitalProduct.getDetails()?.getFileSize());
对比继承的简单示例(仅作对比参考)
// 商品基类
class BaseProduct {
name: string;
price: number;
constructor(name: string, price: number) {
this.name = name;
this.price = price;
}
}
// 实体商品子类
class PhysicalProduct extends BaseProduct {
weight: number;
constructor(name: string, price: number, weight: number) {
super(name, price);
this.weight = weight;
}
getWeight() {
return this.weight;
}
}
// 虚拟商品子类
class DigitalProduct extends BaseProduct {
fileSize: number;
constructor(name: string, price: number, fileSize: number) {
super(name, price);
this.fileSize = fileSize;
}
getFileSize() {
return this.fileSize;
}
}
从上述代码可以看出,继承方式下子类紧密依赖基类,而组合方式更灵活,便于维护和扩展。