SoFunction
Updated on 2025-03-05

Go generic application factory method and generic use

Preface

Since there are too many articles on the use of generics on the Internet, I won’t talk about how to use generics here. Today we combine them withFactory method + generic methodLet’s take a look at how generics are used in business scenarios. The points involved in this article are as follows:

  • How does interfaces implement generalized programming.
  • How does generics solve the limitations of interfaces?
  • The best time to use generics.
  • Simple suggestions on functional design.

Without further ado, let’s start. Please check the relevant information for details on how to use generics and syntax.

Generalized programming of interfaces

When we write structures and methods, we usually use specific types:Either it is a basic type or a custom type. However, if you want to write code that can be applied to multiple types, this limitation will be more restrictive to the program.

So we want to compile some generalized methods and interfaces, what should we do?At this time, we thought of interfaces. If the parameter of the method is an interface, not a structure, the restrictions on the program will be much relaxed. Because any structure that implements this interface can be used as an interface parameter of this method, it can ensure that when other similar functions are added later, you only need to implement this interface to meet the needs.

For example, the following requirement:

Define the two mobile phone brand structures Huawei and Apple, and print out the names of their respective brands. Ensure the scalability of the program, we may also add Xiaomi later

import "fmt"
//Unitative interface of mobile phonetype Phone interface {
  PrintBrand()
}
​
type HuaweiPhone struct {
}
func (hw *HuaweiPhone) PrintBrand() {
  ("Brand Name: Huawei")
}
​
type Iphone struct {
}
func (ip *Iphone) PrintBrand() {
  ("Brand Name: Apple")
}
//Unified printing methodfunc PrintBrand(phone Phone) {
  ()
}
func main() {
  hw := HuaweiPhone{}
  ip := Iphone{}
  PrintBrand(ip)
  PrintBrand(hw)
}

As mentioned above, we define the structure of two mobile phone brands. If we want to print the brand names of each mobile phone, we need to call the unified printing method. If other brands are added later, we only need to implement it.PhoneThis interface is OK.Add Xiaomi mobile phone brand as follows:

type XiaomiPhone struct {
}
func (xm XiaomiPhone) PrintBrand() {
  ("Brand Name: Xiaomi")
}

We can see from the above code that some generalized behaviors can also be defined through the interface.

Factory + generics to implement more generalized programming

But sometimes, even if we use interfaces, the constraints on the program are still strong, because once we specify a specific interface, we will require us to use a specific interface. And we want to write more general code to make the code applicable toSome kind of unspecific type, not a specific interface or structure. What should I do?

For example, we continue to increase demand based on the above requirements

As the brands we connect with have increased to 20, in addition to the above three, there are Meizu, Samsung, Nokia and ZTE. . . . etc.

At this time, we can no longer meet the current code, so we thought of the factory design pattern, using generics to generalize all types in the factory, and we print out the specific brand name by passing in the type name. We introduce factory mode to continue to optimize our code,

as follows:

var cache 
//Factory method can be passed in any typefunc PhoneFactory[T any]() (t *T) {
  target := (t)
  v, ok := (t)
  if ok {
    return v.(*T)
  }
  v = new(T)
  v, _ = (target, v)
  return v.(*T)
}
func main() {
  PrintBrand(PhoneFactory[Iphone]())
  PrintBrand(PhoneFactory[HuaweiPhone]())
  PrintBrand(PhoneFactory[XiaomiPhone]())
}

In the code, we wrote a factory method. The generic type is any, which receives any type. In the factory, we create an object to return the corresponding type and cache the type object to prevent repeated creation. In this way, when we add other categories later, we can create them uniformly through this factory method, and we can also do some operations based on business needs through reflection before and after creation.

The best time to use generics

The addition of generics undoubtedly increases the complexity of the code. So when is the best time to use generics?

Ian Lance Taylor, the main designer of Go generics, gave a brief generic usage policy.When developers find that they write the exact same code multiple times, and the only difference between these copies is that they use different types, they can consider using type parameters. In other words, developers should avoid using type parameters until they find themselves writing the exact same code multiple times.

Simple suggestions on functional design

For example, the above business is actually enough when we start designing it to the interface level. If the factory method is introduced from the beginning, it is actually considered over-design. The principle of our design of a function is,Grasp the context and design appropriately, because once we put too much energy into flexible design, it will inevitably affect the needs that should have been completed. At the same time, too many features will introduce more potential problems, and fixing them will also take our time and energy. And this is even more true in the current era of agile development.

at last

In order to improve readability, the above codes are presented in the simplest way. The actual business is much more complicated than this. Here is just a direction.

This is the article about Go generic application factory methods and generic use. For more relevant Go generic application content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!