面试题答案
一键面试运用Go组合实现代码复用的方式
- 定义基础结构体:
- 针对商品管理模块,可以定义
Product
结构体,包含商品的基本信息,如ID
、Name
、Price
等。
type Product struct { ID int Name string Price float64 }
- 对于订单处理模块,定义
Order
结构体,订单可能包含多个商品,因此可以组合Product
结构体的切片。
type Order struct { OrderID int Products []Product TotalCost float64 }
- 针对商品管理模块,可以定义
- 方法定义:
- 在商品管理模块,可以为
Product
定义方法,如计算商品折扣后的价格。
func (p *Product) CalculateDiscountedPrice(discount float64) float64 { return p.Price * (1 - discount) }
- 在订单处理模块,为
Order
定义方法,如计算订单总价格。
func (o *Order) CalculateTotalCost() { total := 0.0 for _, product := range o.Products { total += product.Price } o.TotalCost = total }
- 在商品管理模块,可以为
- 复用方式:
- 通过组合,
Order
结构体可以直接使用Product
结构体的方法。例如,在计算订单中商品的折扣总价时,可以遍历Order
中的Products
,调用Product
的CalculateDiscountedPrice
方法。
func (o *Order) CalculateDiscountedTotalCost(discount float64) { total := 0.0 for _, product := range o.Products { total += product.CalculateDiscountedPrice(discount) } o.TotalCost = total }
- 通过组合,
可能遇到的问题及解决方案
- 命名冲突:
- 问题:不同模块中可能定义了相同名称的结构体或方法,导致命名冲突。
- 解决方案:采用合理的命名空间策略,比如在结构体或方法名前加上模块相关的前缀。例如,商品管理模块的
Product
结构体可以改为ProductGoods
,订单处理模块的Order
结构体可以改为OrderProcessing
。
- 结构体嵌套过深:
- 问题:如果组合方式使用不当,可能导致结构体嵌套层次过多,增加代码复杂度和维护难度。
- 解决方案:尽量保持结构体的简洁和扁平。如果确实需要多层嵌套,可以考虑将部分功能封装成独立的结构体,并提供清晰的接口。例如,对于订单中的商品信息,可以将商品的详细描述封装成一个独立的
ProductDetail
结构体,然后在Product
结构体中组合ProductDetail
,而不是在Product
中直接包含大量的商品描述字段。
- 接口一致性:
- 问题:不同模块间通过组合复用代码时,可能因为接口不一致,导致无法直接复用。
- 解决方案:定义统一的接口。例如,定义一个
Pricable
接口,Product
结构体实现该接口,Order
结构体在处理价格相关逻辑时,接收实现了Pricable
接口的类型。
type Pricable interface { GetPrice() float64 } func (p *Product) GetPrice() float64 { return p.Price } func (o *Order) CalculateTotalCost(pricables []Pricable) { total := 0.0 for _, p := range pricables { total += p.GetPrice() } o.TotalCost = total }
这样,即使未来有新的类型需要参与价格计算,只要实现Pricable
接口,就可以方便地复用Order
的价格计算逻辑。