MST

星途 面试题库

面试题:TypeScript 组合与继承在复杂场景下的权衡

现有一个电商系统,有 `Product` 类表示商品,`Cart` 类表示购物车,`Order` 类表示订单。`Product` 有价格、名称等属性,`Cart` 会添加、移除 `Product`,`Order` 基于 `Cart` 的商品信息生成订单。假设业务需求变更,需要给 `Product` 增加库存管理功能,同时部分 `Cart` 操作需要记录日志。请阐述在这种场景下,组合和继承分别该如何设计,哪种方式更优,并给出 TypeScript 代码示例。
44.5万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

组合设计

  1. 设计思路
    • 对于Product类的库存管理功能,创建一个独立的Inventory类,然后在Product类中组合Inventory类的实例。
    • 对于Cart操作记录日志,创建一个CartLogger类,在Cart类中组合CartLogger类的实例。
  2. 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()}`);
        });
    }
}

继承设计

  1. 设计思路
    • 对于Product类的库存管理功能,创建一个StockedProduct类继承Product类,在StockedProduct类中添加库存管理相关属性和方法。
    • 对于Cart操作记录日志,创建一个LoggingCart类继承Cart类,在LoggingCart类中重写添加和移除商品的方法,并在其中添加日志记录功能。
  2. 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()}`);
        });
    }
}

哪种方式更优

组合方式更优,原因如下:

  1. 灵活性更高:组合方式使得代码更加灵活,各个功能模块可以独立变化。例如,如果库存管理逻辑需要修改,只需要修改Inventory类,而不会影响Product类的其他功能。而继承方式下,如果父类Product有较大改动,可能会影响到StockedProduct等子类。
  2. 代码复用性更好:组合方式可以在不同的类中复用相同的功能模块,如CartLogger可以被多个不同的类复用。而继承方式下,子类会继承父类所有的属性和方法,可能导致子类包含一些不需要的功能,增加了代码的复杂性。
  3. 遵循合成复用原则:组合方式更符合合成复用原则,尽量使用对象组合而不是继承来达到复用的目的,这样可以降低类之间的耦合度。