[Genérico avanzado] Método de fábrica de Go Aplicación genérica + Evolución del uso genérico

  Hola a todos, soy Coder, hoy vamos a hablar sobre los genéricos, vamos, los genéricos se han perfeccionado en diez años, y diez años no es mucho. Después de todo, Conan todavía es un estudiante de primaria, y no lo es. demasiado corto Sí, jajaja.

Dado que hay demasiados artículos sobre el uso de genéricos en Internet, no hablaremos sobre cómo usar los genéricos aquí. Hoy combinaremos el método de fábrica + el método genérico para ver cómo se usan los genéricos en escenarios comerciales. Los puntos que trata este artículo son los siguientes:

  1. ¿Cómo implementa una interfaz la programación generalizada?
  2. Cómo los genéricos resuelven las limitaciones de las interfaces.
  3. El mejor momento para usar genéricos.
  4. Sencillos consejos sobre diseño funcional.

Sin más preámbulos, comencemos. Cómo usar los genéricos y su sintaxis, verifique la información relevante usted mismo.

Interfaz para lograr una programación generalizada

  Por lo general, cuando escribimos estructuras y métodos, generalmente usamos tipos específicos: tipos básicos o tipos personalizados . Pero si desea escribir código que se pueda aplicar a varios tipos de código, entonces esta restricción será más restrictiva para el programa.

  Entonces, queremos compilar algunos métodos e interfaces generalizados, ¿qué debemos hacer? En este momento, pensamos en la interfaz, si el parámetro del método es una interfaz en lugar de una estructura, las restricciones en el programa se liberarán mucho. Debido a que cualquier estructura que implemente esta interfaz se puede usar como parámetro de interfaz de este método, se puede garantizar que cuando se agreguen otras funciones similares más adelante, solo se puede implementar esta interfaz para cumplir con los requisitos.

Por ejemplo el siguiente requisito:

Defina dos estructuras de marcas de teléfonos móviles, Huawei y Apple, e imprima los nombres de sus respectivas marcas. Para garantizar la escalabilidad del programa, también podemos agregar Xiaomi más adelante

import "fmt"
//手机统一接口
type Phone interface {
  PrintBrand()
}
​
type HuaweiPhone struct {
}
func (hw *HuaweiPhone) PrintBrand() {
  fmt.Printf("品牌名字:华为")
}
​
type Iphone struct {
}
func (ip *Iphone) PrintBrand() {
  fmt.Printf("品牌名字:苹果")
}
//统一打印方法
func PrintBrand(phone Phone) {
  phone.PrintBrand()
}
​
func main() {
  hw := HuaweiPhone{}
  ip := Iphone{}
  PrintBrand(ip)
  PrintBrand(hw)
}
复制代码

Como se muestra en el código anterior, definimos la estructura de dos marcas de teléfonos móviles. Si queremos imprimir el nombre de la marca de cada teléfono móvil, debemos llamar al método de impresión unificado. Si se agregan otras marcas más tarde, solo necesitamos implementar Phoneesta interfaz, de la siguiente manera Agregar marca de teléfono Xiaomi:

type XiaomiPhone struct {
}
func (xm XiaomiPhone) PrintBrand() {
  fmt.Printf("品牌名字:小米")
}
复制代码

Podemos ver en el código anterior que algunos comportamientos generalizados también se pueden definir a través de interfaces.

Factory + genéricos para una programación más generalizada

  可是有时候,即便我们使用了接口,对程序的约束依然还是很强,因为一旦我们指明了具体的接口,就会要求我们必须使用特定的接口。而我们希望编写更通用的代码,要使代码能够应用于某种不具体的类型,而不是具体的一个接口或者结构体。这个要怎么办呢?

比如,我们基于以上的需求继续加需求

由于我们对接的品牌增大到20种,除了上面三种还有 魅族、三星、诺基亚、中兴。。。。等等

这个时候我们基于当前的代码已经不能满足,那么我们想到了工厂设计模式,在工厂中用泛型来泛化所有的类型,我们通过传入类型名字来打印出具体的品牌名。我们引入工厂模式继续优化我们的代码,如下:

var cache sync.Map
//工厂方法 可以传入任意的类型
func PhoneFactory[T any]() (t *T) {
  target := reflect.TypeOf(t)
  v, ok := cache.Load(t)
  if ok {
    return v.(*T)
  }
  v = new(T)
  v, _ = cache.LoadOrStore(target, v)
  return v.(*T)
}
func main() {
  PrintBrand(PhoneFactory[Iphone]())
  PrintBrand(PhoneFactory[HuaweiPhone]())
  PrintBrand(PhoneFactory[XiaomiPhone]())
}
复制代码

代码中我们编写了个工厂方法,泛型类型为 any, 接收任意的类型,在工厂中我们创建对象返回相应的类型并缓存类型对象防止重复创建。这样我们后面再加其他类别的时候可以通过这个工厂方法来统一的创建,我们还可以通过反射在创建前后根据业务需要做一些操作。

泛型使用的最佳时机

  泛型的加入,无疑增加了代码的复杂度,那么我们使用泛型的最佳时机是什么时候呢?

  Go 泛型主要设计者 Ian Lance Taylor 给出了简要的泛型使用方针,当开发者发现自己多次编写完全相同的代码,而这些副本之间的唯一区别仅在于使用了不同类型,这时候便可以考虑使用类型参数。换句话说,即开发者应避免使用类型参数,直到发现自己要多次编写完全相同的代码。

关于功能设计的简单建议

  比如说上面的业务,其实我们开始设计的时候设计到接口层面就可以了,如果一开始就引入工厂方法,其实这算是过度设计,我们设计一个功能的原则是,抓住上下文,适度设计,因为一旦我们投入了过多的精力到灵活设计上,势必会影响本应该完成的需求。同时,过多的功能会引入更多潜在的问题,而修复问题也会耗费我们的时间和精力。而且在当前这个敏捷开发的时代,更是如此。

最后

  感谢各位能看到最后,希望本篇的内容对你有帮助,有什么意见或者建议可以留言一起讨论,看到后第一时间回复,也希望大家能给个赞,你的赞就是我写文章的动力,再次感谢。

为了提高可阅读性,以上代码都是以最简单的方式呈现的,实际业务远比这要复杂的多,这里只是提供一种方向。

本文正在参加技术专题18期-聊聊Go语言框架

Supongo que te gusta

Origin juejin.im/post/7120104935953285134
Recomendado
Clasificación