在 Golang 中使用多态与 switch?

问题描述 投票:0回答:1

我有一个允许客户购买汽车的端点。

PurchaseReq
结构看起来像这样:

type PurchaseReq struct {
    Customer    string
    SalesRep    string
    Location    string
    Brand       string
    Model       string
    AddOns      map[string]bool
}

PurchaseOrder
结构看起来像这样

type PurchaseOrder struct {
    Customer    string
    SalesRep    string
    Price       int
    Brand       string
    Model       string
    AddOns      map[string]bool
    AfterSales  map[string]string
}

Buy
函数看起来像这样。我目前使用 switch 语句来处理所有不同的品牌。价格和售后代表取决于品牌、地点等

func Buy(purchaseReq *PurchaseReq) error {
    var price int
    switch purchaseReq.Brand {
    case "Ford":
        price = getPriceFromFord(purchaseReq.Brand, purchaseReq.Model, purchaseReq.AddOns)
    case "Ferrari":
        price = getPriceFromFerrari(purchaseReq.Brand, purchaseReq.Model, purchaseReq.AddOns)
    // ...
    default:
        return fmt.Errorf("invalid brand %s", purchaseReq.Brand)
    }
    afterSalesReps := getRepsFromStore(purchaseReq.Location, purchaseReq.Brand, purchaseReq.Model)
    return order.New(&PurchaseOrder{
        Customer      : purchaseReq.Customer,
        SalesRep      : purchaseReq.SalesRep,
        Brand         : purchaseReq.Brand,
        Model         : purchaseReq.Model,
        AddOns        : purchaseReq.AddOns,
        Price         : price,
        AfterSalesReps: afterSalesReps,
    })
}

实际的结构比这复杂一点,每个汽车品牌都有更多的自定义逻辑。我还有大约 15 个汽车品牌在售。

通常我会使用多态性,所以我会

type Car interface{
    Price() int
}

type Ford struct {}

func (f *Ford) Price() int { ... }

type Ferrari struct {}

func (f *Ferrari) Price() int { ... }

我的问题是,通过这个实现,我仍然会在

car.New
而不是
Buy
中有一个非常长的开关块。

func Buy(purchaseReq *PurchaseReq) error {
    c := car.New(purchaseReq)
    afterSalesReps := getRepsFromStore(purchaseReq.Location, purchaseReq.Brand, purchaseReq.Model)
    po := &PurchaseOrder{
        Customer      : purchaseReq.Customer,
        SalesRep      : purchaseReq.SalesRep,
        Brand         : purchaseReq.Brand,
        Model         : purchaseReq.Model,
        AddOns        : purchaseReq.AddOns,
        Price         : c.Price(),
        AfterSalesReps: afterSalesReps,
    }
    return order.New(po)
}

func New(purchaseReq *purchaseReq) *Car {
    switch purchaseReq.Brand {
    case "Ford":
        return &Ford{ ... }
    case "Ferrari":
        return &Ferrari{ ... }
    // ...
    }
}

我实际上也没有对通用

Car
做任何事情,所以我实际上不需要这个接口。

我不确定实现这种设计的最佳方法是什么。有什么建议吗?

go design-patterns interface polymorphism
1个回答
0
投票

听起来在您的项目背景下可能会遇到多个问题需要解决,所以我将专注于我所看到的,而不是将您引向完全不同的方向。

首先,简化问题,去除不必要的上下文;

我需要将

string
的值链接到构造函数。

我认为实现这种设计的最简洁方法是使用地图,您可以在其中使用品牌“key”,并返回构造它的函数;

brands = map[string]func() Car{
        "Ford":    func() Car { return NewFord() },
        "Ferrari": func() Car { return NewFerrari() },
    }

那么你可以简单地这样称呼它;

someFord := brands["Ford"]()
someFord.GetPrice()

或者

fmt.Println(brands["Ford"]().GetPrice())

显然我没有考虑到您的所有上下文和参数,但我希望这能在某种程度上帮助您实现它。

我在测试时写了一些代码here

© www.soinside.com 2019 - 2024. All rights reserved.