简体   繁体   中英

How to write several implementation of the same method that have a different signature

I have several implementation of the same method SetRateForMeasure :

package repartition

type Repartition interface {
    Name() string
    Compute(meters []models.Meter, totalsProd, totalsConso map[string]float64) []models.Meter
    SetRateForMeasure(meter models.Meter, measure models.Measure, total float64) float64
}

Then, in my code (in repartition.go), I call it:

rate := repartition.SetRateForMeasure(meter, measure, total)

where repartition is the interface defined before.

Thing is, when I add a new implementation of this method, the arguments of my functions might differ.

For example, the static repartition use a static percentage that is only used in this case.

I end up adding parameters so that I have a common interface to all methods, but it results that there is a lot of unused parameters depending on the implementation.

If I add it to common interface, it will be unused for the other definitions.

I tried to remove this method from my interface definition, but now

rate := repartition.SetRateForMeasure()

is no more defined.

How should I organize my code?

There is no function overloading in Go, so you cannot declare the same function with different arguments. There's a few ways you can implement this though:

  • You can add multiple functions with different names and signatures
  • You can change the function to accept a struct instead of arguments
SetRateForMeasure(args SetRateOptions) float64

type SetRateOptions struct {
 Meter models.Meter
 Measure models.Measure
 Total float64
 Percentage *float64 // If nil, use default percentage
 ... // more parameters as needed
}

Go doesn't support method overriding. You either define methods with different names that take different parameters or you can declare the method to accept a parameter struct.

type SetRateParams struct {
    Meter    models.Meter
    Measure  models.Measure
    Total    float64
}

type Repartition interface {
    SetRateForMeasure(params SetRateParams) float64
}

Optionally, you can declare params in your structs as pointers, so you can represent "not-provided" semantics with nil instead of using the zero-value. This might be relevant in case of numerical params where 0 could be a valid value.

Using a struct param has also the advantage that you don't have to change all the call sites in case you decide to add an additional param 6 months from now (you just add it to the struct).

There are also worse solutions with interface{} varargs, for the sake of stating what is possible, but unless you loathe type safety, I wouldn't recommend that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM