Introduccion

1

Patrones Creacionales: Diseñando Objetos con Propósito

2

Patrones de Diseño Creacionales: Singleton y Factory

Singleton

3

Patrón Singleton: Cómo Garantizar Única Instancia de Clase en Java

4

Diagramas de Clases en UML para Patrones de Diseño

5

Patrones de Diseño en TypeScript: Singleton y Más

6

Patrones de diseño: Pros y contras del Singleton

Factory

7

Patrones de Diseño: Fábrica y Creación de Objetos

8

"Implementación de Patrón Factory en Programación Orientada a Objetos"

9

Implementación de Factory Method en JavaScript

10

Diferencias entre patrón Factory en JavaScript y TypeScript

11

Patrón Factory en Programación Orientada a Objetos

Abstract Factory

12

Patrón Abstract Factory en Producción de Coches

13

Patrones de Diseño: Implementación de Abstract Factory en Java

14

Programación Orientada a Objetos con JavaScript: Patron Abstract Factory

15

Diferencias clave entre clases e interfaces en TypeScript

16

Patrón Abstract Factory: Ventajas y Desventajas

Builder

17

Patrón Builder: Diseño de Objetos en Pasos Secuenciales

18

Patrón Builder: Diseño y Uso en Desarrollo de Software

19

Patrón Builder en Producción de Coches: JavaScript vs TypeScript

20

Transformación de Promesas en JavaScript a TypeScript

21

Patrones de Diseño: Uso del Patrón Builder en Java

Prototype

22

Clonación de objetos con el patrón Prototype

23

Clonación de objetos en JavaScript y TypeScript

24

Patrón Prototype: Clonación de Objetos en JavaScript

25

Diferencias entre Prototype en JavaScript y TypeScript

26

Clonación y Modificación de Objetos en JavaScript

Conclusiones

27

Patrones Creacionales en Diseño de Software

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Clonación y Modificación de Objetos en JavaScript

26/27
Recursos

¿Cuáles son los beneficios del patrón Prototype?

El patrón Prototype es una herramienta poderosa en el diseño de software que permite clonar objetos de manera eficiente. Una de sus ventajas principales es que podemos crear copias de objetos complejos sin asociarnos a sus clases concretas, lo cual fomenta la flexibilidad en el desarrollo. Por ejemplo:

  • Independencia de clases concretas: Podemos clonar un objeto como un coche o un rinoceronte sin mencionar sus clases específicas. Esto se logra porque estos objetos extienden de una clase base.

  • Reducción de subclases: En lugar de crear múltiples subclases para diferentes configuraciones, simplemente clonamos un objeto base y modificamos sus propiedades. Esto es extremadamente útil al tratar con objetos complejos con numerosas propiedades.

  • Eficiencia en instanciación: Si necesitamos múltiples versiones de un objeto, evitar la repetición del código de instanciación es crucial. Así se omiten los inconvenientes de pasar numerosos parámetros al constructor, lo que facilita el desarrollo.

¿Qué desafíos presenta la implementación del patrón Prototype?

A pesar de sus beneficios, implementar el patrón Prototype no está exento de desafíos. Entre los cuales se encuentran:

  • Complejidad en la clonación: Aunque en muchos casos es sencillo copiar una instancia, algunas situaciones requieren un proceso de clonación más complejo, que puede incluir llamadas a API y otras consideraciones.

  • Referencias circulares: En objetos compuestos por otros objetos, puede haber problemas con referencias circulares. Si un objeto compuesto por otros objetos es clonado, pueden surgir problemas si alguna clase clonada forma parte de la composición original, lo que demanda una gestión cuidadosa.

¿Cuándo es recomendable usar el patrón Prototype?

El patrón Prototype es particularmente útil cuando buscamos:

  • Reducir subclases: Al minimizar la cantidad de subclases, el código se simplifica y se vuelve más manejable.

  • Fomentar la reutilización: Clonar objetos establecidos ayuda a maximizar la reutilización de componentes en diferentes contextos. La reutilización y extensibilidad son cruciales en el buen diseño de software, como se recalca constantemente en los patrones de diseño.

¿Cómo se relaciona JavaScript con el patrón Prototype?

JavaScript ofrece soporte nativo para el patrón Prototype, facilitando tareas como la clonación profunda (deep clone) de objetos. Al clonar un objeto en JavaScript, no es necesario instanciarlo de nuevo; basta con pasar el objeto a una función de clonación. Esta característica resalta las capacidades de JavaScript en cuanto a la gestión de objetos, optimizando el uso de recursos y el tiempo de implementación.

Para los desarrolladores que trabajan con JavaScript o TypeScript, este paradigma provee una metodología eficiente para gestionar objetos complejos. Se insta a los desarrolladores a experimentar con la clonación de objetos como parte de su aprendizaje, ya que el proceso promueve la flexibilidad y personalización del código.

Te animamos a compartir tus soluciones y creatividad en comentarios, fomentando un enriquecedor intercambio de ideas sobre el patrón Prototype y los patrones de diseño creacionales.

Aportes 4

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

¡Hola!

Te dejo mi código ejemplo aplicando en typescript el patrón de diseño prototype a una clase de la cuál tiene una relación de composición con otras clases:

class Person {
  private name: string;
  private lastName: string;
  constructor(name, lastName) {
    this.name = name;
    this.lastName = lastName;
  }
  get getName() {
    return this.name;
  }
  get getLastName() {
    return this.lastName;
  }
}

class User {
  private username: string;
  private creationDateUser: string;
  constructor(username) {
    this.username = username;
    const timeInMilisecs = Date.now();
    const date = new Date(timeInMilisecs);
    this.creationDateUser = date.toISOString();
  }
  get getUsername() {
    return this.username;
  }
  get getCreationDateUser() {
    return this.creationDateUser;
  }
}

class UserConfiguration {
  private directory: string;
  private homeFolder: string;
  constructor(directory, homeFolder) {
    this.directory = directory;
    this.homeFolder = homeFolder;
  }
  get getDirectory() {
    return this.directory;
  }
  get getHomeFolder() {
    return this.homeFolder;
  }
}

interface ICompleteUserProps {
  name: string;
  lastName: string;
  username: string;
  directory: string;
  homeFolder: string;
}

class CompleteUser {
  user: User;
  person: Person;
  userConfiguration: UserConfiguration;
  constructor({
    name,
    lastName,
    username,
    directory,
    homeFolder,
  }: ICompleteUserProps) {
    this.person = new Person(name, lastName);
    this.user = new User(username);
    this.userConfiguration = new UserConfiguration(directory, homeFolder);
    console.log('User created successfully, details:\n', this);
  }
  public clone() {
    const props: ICompleteUserProps = {
      name: this.person.getName,
      lastName: this.person.getLastName,
      username: this.user.getUsername,
      directory: this.userConfiguration.getDirectory,
      homeFolder: this.userConfiguration.getHomeFolder,
    };

    return new CompleteUser(props);
  }
}

const createOriginalObjectAndPrototype = ({
  name,
  lastName,
  username,
  directory,
  homeFolder,
}: ICompleteUserProps) => {
  const originalUser = new CompleteUser({
    name,
    lastName,
    username,
    directory,
    homeFolder,
  });
  const userClone = originalUser.clone();
  console.log(
    originalUser === userClone
      ? 'They are the same'
      : 'Different objects, prototype working'
  );
};

createOriginalObjectAndPrototype({
  name: 'Alvaro',
  lastName: 'Garzon',
  username: 'Alvaro8317',
  directory: 'home',
  homeFolder: 'alvaro8317',
});

Si lo prefieres, también subí el código a github

Solución 😄…
Se implementa Rhino y se aumenta engine como un atributo adicional.
.

También pueden compilar código TS en línea, en el siguiente enlace: https://www.typescriptlang.org/play

type AvailableColors = "red" | "black" | "gray" | "default";
type EditionsType = "cvt" | "signature" | "default";
type EngineType = "electric" | "gasoline" | "diesel";
type CarConstructorParams = {
  edition: EditionsType;
  model: string;
  airBags: number;
  color: AvailableColors;
  engine: EngineType;
};
abstract class CarTS {
  private _edition: EditionsType;
  private _model: string;
  private _airBags: number;
  private _color: AvailableColors;
  private _engine: EngineType;

  constructor({
    edition,
    model,
    airBags,
    color,
    engine,
  }: CarConstructorParams) {
    this._edition = edition || "default";
    this._model = model || "";
    this._airBags = airBags || 0;
    this._color = color || "default";
    this._engine = engine || "gasoline";
  }

  set airBags(howMany: number) {
    this._airBags = howMany;
  }

  set color(color: AvailableColors) {
    this._color = color;
  }

  set model(model: string) {
    this._model = model;
  }

  set edition(edition: "cvt" | "signature" | "default") {
    this._edition = edition;
  }

  set engine(type: EngineType) {
    this._engine = type;
  }

  get airBags() {
    return this._airBags;
  }

  get color() {
    return this._color;
  }

  get model() {
    return this._model;
  }

  get edition() {
    return this._edition;
  }

  get engine() {
    return this._engine;
  }

  abstract clone(): CarTS;
}

class MastodonCarTS extends CarTS {
  constructor(carToClone?: MastodonCarTS);
  constructor(carToClone: MastodonCarTS) {
    super({
      edition: carToClone?.edition,
      color: carToClone?.color,
      model: carToClone?.model,
      airBags: carToClone?.airBags,
      engine: carToClone?.engine,
    });
  }

  clone(): MastodonCarTS {
    return new MastodonCarTS(this);
  }
}

class RhinoCarTS extends CarTS {
  constructor(carToClone?: RhinoCarTS);
  constructor(carToClone: RhinoCarTS) {
    super({
      edition: carToClone?.edition,
      color: carToClone?.color,
      model: carToClone?.model,
      airBags: carToClone?.airBags,
      engine: carToClone?.engine,
    });
  }

  clone(): RhinoCarTS {
    return new RhinoCarTS(this);
  }
}

class DirectorTS {
  private productionLine!: CarProductionLineTS;

  setProductionLine(productionLine: CarProductionLineTS) {
    this.productionLine = productionLine;
  }

  constructCvtEdition() {
    this.productionLine.setAirBags(4);
    this.productionLine.setColor("red");
    this.productionLine.setEdition("CVT");
  }

  constructSignatureEdition() {
    this.productionLine.setAirBags(8);
    this.productionLine.setColor("gray");
    this.productionLine.setEdition("signature");
  }
}

interface CarProductionLineTS {
  setAirBags(howMany: number): void;
  setColor(color: AvailableColors): void;
  setEdition(edition: string): void;
  resetProductionLine(car: CarTS): void;
}

type ConstructorParams = { factory: FactoryTS };
class SedanProductionLineTS implements CarProductionLineTS {
  private sedanCar!: CarTS;
  private carFactory!: FactoryTS;

  constructor({ factory }: ConstructorParams) {
    this.carFactory = factory;
    this.resetProductionLine(this.carFactory.create());
  }

  resetProductionLine(car: CarTS): void {
    this.sedanCar = car;
  }

  setAirBags(howMany: number): SedanProductionLineTS {
    this.sedanCar.airBags = howMany;
    return this;
  }

  setColor(color: AvailableColors): SedanProductionLineTS {
    this.sedanCar.color = color;
    return this;
  }

  setEdition(edition: EditionsType): SedanProductionLineTS {
    this.sedanCar.edition = edition;
    return this;
  }

  setModel(): SedanProductionLineTS {
    this.sedanCar.model = "sedan";
    return this;
  }

  setEngine(engine: EngineType): SedanProductionLineTS {
    this.sedanCar.engine = engine;
    return this;
  }

  build(): CarTS {
    this.setModel();
    const sedanCar = this.sedanCar;
    this.resetProductionLine(this.carFactory.create());
    return sedanCar;
  }
}

interface FactoryTS {
  create(): CarTS;
}

class MastodonCarFactoryTS implements FactoryTS {
  create(): CarTS {
    return new MastodonCarTS();
  }
}

class RhinoCarFactoryTS implements FactoryTS {
  create(): CarTS {
    return new RhinoCarTS();
  }
}

function appBuilderTS(director: DirectorTS) {
  const mastodonSedanProductionLine = new SedanProductionLineTS({
    factory: new MastodonCarFactoryTS(),
  });
  director.setProductionLine(mastodonSedanProductionLine);
  director.constructCvtEdition();
  const mastodonSedanCvt = mastodonSedanProductionLine
    .setEngine("diesel")
    .build();
  console.log(mastodonSedanCvt);
  const mastodonSedanCvtPrototype = mastodonSedanCvt.clone();
  console.log(mastodonSedanCvtPrototype);

  director.constructSignatureEdition();
  const mastodonSedanSignature = mastodonSedanProductionLine.build();
  console.log(mastodonSedanSignature);
  const mastodonSedanSignaturePrototype = mastodonSedanSignature.clone();
  console.log(mastodonSedanSignaturePrototype);

  const rhinoSedanProductionLine = new SedanProductionLineTS({
    factory: new RhinoCarFactoryTS(),
  });
  director.setProductionLine(rhinoSedanProductionLine);
  director.constructCvtEdition();
  const rhinoSedanCvt = rhinoSedanProductionLine.setEngine("electric").build();
  console.log(rhinoSedanCvt);
  const rhinoSedanCvtPrototype = rhinoSedanCvt.clone();
  console.log(rhinoSedanCvtPrototype);

  director.constructSignatureEdition();
  const rhinoSedanSignature = rhinoSedanProductionLine.build();
  console.log(rhinoSedanSignature);
  const rhinoSedanSignaturePrototype = rhinoSedanSignature.clone();
  console.log(rhinoSedanSignaturePrototype);
}

appBuilderTS(new DirectorTS());
Yo puedo darles como ejemplo práctico de uso, la clonación de de un objeto para modificarlo en un formulario, si el usuario acepta, el clon remplaza al nuevo, si no se revierte los cambios y se borra el clon.
Excelente, el prototype me resulto algo mas amigable a la hora de poder implementar una dependencia, solamente tendría que pasar la instancia y el objeto estaría clonado, aunque este solamente se utilice para patrones específicos.