面试题答案
一键面试组合设计
- 设计思路:
- 对于
Product
类的库存管理功能,创建一个独立的Inventory
类,然后在Product
类中组合Inventory
类的实例。 - 对于
Cart
操作记录日志,创建一个CartLogger
类,在Cart
类中组合CartLogger
类的实例。
- 对于
- TypeScript代码示例:
class Inventory {
private stock: number;
constructor(initialStock: number) {
this.stock = initialStock;
}
getStock() {
return this.stock;
}
updateStock(amount: number) {
this.stock += amount;
}
}
class CartLogger {
log(message: string) {
console.log(`Cart操作日志: ${message}`);
}
}
class Product {
private price: number;
private name: string;
private inventory: Inventory;
constructor(price: number, name: string, initialStock: number) {
this.price = price;
this.name = name;
this.inventory = new Inventory(initialStock);
}
getPrice() {
return this.price;
}
getName() {
return this.name;
}
getInventory() {
return this.inventory;
}
}
class Cart {
private products: Product[] = [];
private cartLogger: CartLogger;
constructor() {
this.cartLogger = new CartLogger();
}
addProduct(product: Product) {
this.products.push(product);
this.cartLogger.log(`添加商品: ${product.getName()}`);
}
removeProduct(product: Product) {
const index = this.products.indexOf(product);
if (index!== -1) {
this.products.splice(index, 1);
this.cartLogger.log(`移除商品: ${product.getName()}`);
}
}
getProducts() {
return this.products;
}
}
class Order {
private cart: Cart;
constructor(cart: Cart) {
this.cart = cart;
}
generateOrder() {
console.log('基于购物车商品信息生成订单');
const products = this.cart.getProducts();
products.forEach(product => {
console.log(`商品: ${product.getName()}, 价格: ${product.getPrice()}`);
});
}
}
继承设计
- 设计思路:
- 对于
Product
类的库存管理功能,创建一个StockedProduct
类继承Product
类,在StockedProduct
类中添加库存管理相关属性和方法。 - 对于
Cart
操作记录日志,创建一个LoggingCart
类继承Cart
类,在LoggingCart
类中重写添加和移除商品的方法,并在其中添加日志记录功能。
- 对于
- TypeScript代码示例:
class Product {
private price: number;
private name: string;
constructor(price: number, name: string) {
this.price = price;
this.name = name;
}
getPrice() {
return this.price;
}
getName() {
return this.name;
}
}
class StockedProduct extends Product {
private stock: number;
constructor(price: number, name: string, initialStock: number) {
super(price, name);
this.stock = initialStock;
}
getStock() {
return this.stock;
}
updateStock(amount: number) {
this.stock += amount;
}
}
class Cart {
private products: Product[] = [];
addProduct(product: Product) {
this.products.push(product);
}
removeProduct(product: Product) {
const index = this.products.indexOf(product);
if (index!== -1) {
this.products.splice(index, 1);
}
}
getProducts() {
return this.products;
}
}
class LoggingCart extends Cart {
log(message: string) {
console.log(`Cart操作日志: ${message}`);
}
addProduct(product: Product) {
super.addProduct(product);
this.log(`添加商品: ${product.getName()}`);
}
removeProduct(product: Product) {
super.removeProduct(product);
this.log(`移除商品: ${product.getName()}`);
}
}
class Order {
private cart: Cart;
constructor(cart: Cart) {
this.cart = cart;
}
generateOrder() {
console.log('基于购物车商品信息生成订单');
const products = this.cart.getProducts();
products.forEach(product => {
console.log(`商品: ${product.getName()}, 价格: ${product.getPrice()}`);
});
}
}
哪种方式更优
组合方式更优,原因如下:
- 灵活性更高:组合方式使得代码更加灵活,各个功能模块可以独立变化。例如,如果库存管理逻辑需要修改,只需要修改
Inventory
类,而不会影响Product
类的其他功能。而继承方式下,如果父类Product
有较大改动,可能会影响到StockedProduct
等子类。 - 代码复用性更好:组合方式可以在不同的类中复用相同的功能模块,如
CartLogger
可以被多个不同的类复用。而继承方式下,子类会继承父类所有的属性和方法,可能导致子类包含一些不需要的功能,增加了代码的复杂性。 - 遵循合成复用原则:组合方式更符合合成复用原则,尽量使用对象组合而不是继承来达到复用的目的,这样可以降低类之间的耦合度。