Constructores

Cuando los constructores en un contexto OOP están sobrecargados, es mejor utilizar el patrón Factory Pattern para que el código sea limpio.

Mira este pedazo de constructor:

export class Grupo extends Entity {
  readonly slug: string
  readonly url: string
  constructor(
    readonly id: number,
    readonly title: string,
    readonly SEOTitle: string,
    readonly description: string,
    readonly SEODescription: string,
    readonly image: Image,
    readonly bgPosition: number,
    readonly latitude: number,
    readonly longitude: number,
    readonly point: MapPoint,
    readonly totalPrice: string,
    readonly totalTime: number | null,
    readonly sabiasque: SabiasQue[] | null,
    readonly zona: Zona | null,
    readonly startDate: Date | null,
    readonly endDate: Date | null,
    readonly showWeather: boolean,
    readonly gallery: Image[] | null,
    readonly pois: Poi[],
    readonly grupos: Grupo[],
    readonly rutas: Ruta[],
    readonly office: Oficina | null,
    readonly links: Nullable<{
      wikipedia: string
      youtube: string
      parking: string
      parkingAutocaravana: string
      googleMaps: string
    }> | null,
    readonly featured: boolean | null
  ) {
    super()
    this.slug = this.createSlug(this.SEOTitle)
    this.url = this.getFullUrl(`grupos/${this.id}/${this.slug}`)
  }

Cuando tratas de instanciar una nueva clase, es un follón porque tienes que introducir los argumentos en orden. Primero id, luego title, luego SEOTitle…

Pero lo peor es que si a futuro se añaden nuevos parámetros, tienes que asegurarse de que el orden sea el correcto en TODOS los lugares en los que se instancia esta clase.

Para ello usamos hacemos el constructor privado y utilizamos un Factory Pattern, un método que encapsula al constructor.

export class Grupo extends Entity {
  readonly slug: string
  readonly url: string
  private constructor(
    readonly id: number,
    readonly title: string,
    readonly SEOTitle: string,
    readonly description: string,
    readonly SEODescription: string,
    readonly image: Image,
    readonly bgPosition: number,
    readonly latitude: number,
    readonly longitude: number,
    readonly point: MapPoint,
    readonly totalPrice: string,
    readonly totalTime: number | null,
    readonly sabiasque: SabiasQue[] | null,
    readonly zona: Zona | null,
    readonly startDate: Date | null,
    readonly endDate: Date | null,
    readonly showWeather: boolean,
    readonly gallery: Image[] | null,
    readonly pois: Poi[],
    readonly grupos: Grupo[],
    readonly rutas: Ruta[],
    readonly office: Oficina | null,
    readonly links: Nullable<{
      wikipedia: string
      youtube: string
      parking: string
      parkingAutocaravana: string
      googleMaps: string
    }> | null,
    readonly featured: boolean | null
  ) {
    super()
    this.slug = this.createSlug(this.SEOTitle)
    this.url = this.getFullUrl(`grupos/${this.id}/${this.slug}`)
  }
 
  static create({
    id,
    title,
    SEOTitle,
    description,
    SEODescription,
    image,
    bgPosition,
    latitude,
    longitude,
    point,
    totalPrice,
    totalTime,
    sabiasque,
    zona,
    startDate,
    endDate,
    showWeather,
    gallery,
    pois,
    grupos,
    rutas,
    office,
    links,
    featured
  }: CreateGrupo): Grupo {
    return new Grupo(id, title, SEOTitle, description, SEODescription, image, bgPosition, latitude, longitude, point, totalPrice, totalTime, sabiasque, zona, startDate, endDate, showWeather, gallery, pois, grupos, rutas, office, links, featured)
  }
  
export interface CreateGrupo {
  id: number
  title: string
  SEOTitle: string
  description: string
  SEODescription: string
  image: Image
  bgPosition: number
  latitude: number
  longitude: number
  point: MapPoint
  totalPrice: string
  totalTime: number | null
  sabiasque: SabiasQue[] | null
  zona: Zona | null
  startDate: Date | null
  endDate: Date | null
  showWeather: boolean
  gallery: Image[] | null
  pois: Poi[]
  grupos: Grupo[]
  rutas: Ruta[]
  office: Oficina | null
  links: Nullable<{
    wikipedia: string
    youtube: string
    parking: string
    parkingAutocaravana: string
    googleMaps: string
  }> | null
  featured: boolean | null
}

De esta manera tenemos encapsulada la creación de la clase Grupo. Si necesitamos modificarla en un futuro, solo tenemos que modificarla aquí sin tener que revisar TODAS las llamadas a new Grupo. Otra ventaja es que al usar un objeto en el que añadimos todos los parámetros, no importa el orden de entrada.

new Grupo(id, SEOTitle, title)

Esto daría error, porque el constructor espera que title vaya delante de SEOTitle

Grupo.create({id, SEOTitle, title})

Esto funcionaría correctamente porque enviamos todos los argumentos en un objeto y es el Factory Pattern el que se encarga de instanciar la clase con los parámetros recibidos.