No tienes acceso a esta clase

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

No se trata de lo que quieres comprar, sino de quién quieres ser. Invierte en tu educación con el precio especial

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

12 Días
0 Hrs
6 Min
57 Seg

Singleton: pros y contras

6/27
Recursos

Aportes 52

Preguntas 1

Ordenar por:

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

Les dejo mi codigo en TypeScript:

class Product {
  private id: number;
  private name: string;
  private cost: number;

  constructor(id: number, name: string, cost: number) {
    this.id = id;
    this.name = name;
    this.cost = cost;
  }

  getId() {
    return this.id;
  }

  getName() {
    return this.name;
  }

  getCost() {
    return this.cost;
  }
}

class ShoppingCart {
  private static instance: ShoppingCart;
  private cart: Product[] = [];

  private constructor() {}

  getCart() {
    return this.cart;
  }

  add(product: Product) {
    this.cart.push(product);
  }

  deleteById(id: number) {
    this.cart = this.cart.filter((prod) => prod.getId() !== id);
  }

  static getInstance() {
    if (!this.instance) this.instance = new ShoppingCart();
    return this.instance;
  }
}

(() => {
  const cart = ShoppingCart.getInstance();
  const cart2 = ShoppingCart.getInstance();
  const prod1 = new Product(1, "mate", 3000);
  const prod2 = new Product(2, "bombilla", 2900);
  const prod3 = new Product(3, "matera", 2400);

  // agregamos products al cart
  cart.add(prod1);
  cart.add(prod2);
  cart.add(prod3);

  console.log(cart.getCart());

  // borramos por id
  cart.deleteById(2);

  console.log(cart.getCart());

  // verificamos que ambos cart tienen la misma instancia, por tanto ambos tienen los mismos products
  console.log(cart === cart2);
  console.log(cart.getCart());
  console.log(cart2.getCart());
})();

Hasta este punto del curso, me hubiese gustado profundizar más en diferentes casos de uso que pudiese tener el Patrón Singleton en desarrollo de software, pues de esta manera es como se podría interiorizar el concepto de mejor forma.

Gracias.

Esta version implementa un carrito diferente para cada usuario, utilizando el patron singleton: ```js const PRODUCTS: Product[] = [ { name: "apple", id: 1, cost: 2000 }, { name: "banana", id: 2, cost: 500 }, { name: "coconut", id: 3, cost: 3000 }, { name: "meat", id: 4, cost: 20000 }, { name: "pineapple", id: 5, cost: 1000 }, { name: "coke", id: 6, cost: 1800 }, ] as Product[]; interface Product { id: number; name: string; cost: number; getName(): string; getCost(): number; getId(): number; } interface cart { add(product: Product): void; deleteById(id: number): void; getInstance(client: string): ShoppingCart; } class ShoppingCart implements cart { private products: Product[] = []; private constructor() {} static usersCarts: Record<string, ShoppingCart> = {}; static getInstance(client: string): ShoppingCart { return this.usersCarts[client] ? this.usersCarts[client] : new ShoppingCart(); } add(product: Product): void { this.products.push(product); } deleteById(id: number): void { const productIndex = this.products.findIndex( (product) => product.id === id ); if (productIndex !== -1) { this.products.splice(productIndex, 1); } } getTotal(): number { return this.products.reduce((total, product) => total + product.cost, 0); } } function clientApp() { const cartUser1 = ShoppingCart.getInstance("Client_1"); const cartUser2 = ShoppingCart.getInstance("Client_2"); const cartUser3 = ShoppingCart.getInstance("Client_3"); cartUser1.add(PRODUCTS[0]); cartUser1.add(PRODUCTS[1]); cartUser2.add(PRODUCTS[2]); cartUser2.add(PRODUCTS[3]); cartUser3.add(PRODUCTS[4]); cartUser3.add(PRODUCTS[5]); // Display the cart contents and total cost for each user console.info("Cart Contents and Total Cost for Each User:"); console.log("Client 1 Cart:"); console.log("Cart Contents:", cartUser1); console.log("Total Cost:", cartUser1.getTotal()); console.log("Client 2 Cart:"); console.log("Cart Contents:", cartUser2); console.log("Total Cost:", cartUser2.getTotal()); console.log("Client 3 Cart:"); console.log("Cart Contents:", cartUser3); console.log("Total Cost:", cartUser3.getTotal()); cartUser1.deleteById(PRODUCTS[0].id); cartUser2.deleteById(PRODUCTS[2].id); cartUser3.deleteById(PRODUCTS[4].id); // Display the updated cart contents and total cost for each user console.info("Cart Contents and Total Cost After Deletion for Each User:"); console.log("Client 1 Cart:"); console.log("Cart Contents:", cartUser1); console.log("Total Cost:", cartUser1.getTotal()); console.log("Client 2 Cart:"); console.log("Cart Contents:", cartUser2); console.log("Total Cost:", cartUser2.getTotal()); console.log("Client 3 Cart:"); console.log("Cart Contents:", cartUser3); console.log("Total Cost:", cartUser3.getTotal()); } clientApp(); ```

Usen ChatGPT o Bard de google para solicitarle casos de uso reales, eso me ayudo a entender mejor.

class Product {
    private id: number
    private name: string
    private cost: number

    public constructor(id: number, name: string, cost: number) {
        this.id = id
        this.name = name
        this.cost = cost
    }

    public getName(): string {
        return this.name
    }

    public getCost(): number {
        return this.cost
    }
    
    public getId(): number {
        return this.id
    }
}

class ShoppingCart {
    private static instance: undefined | ShoppingCart
    private products: Product[]
    
    private constructor() {
        this.products = []
    }

    public add(product: Product): void {
        this.products.push(product)
    }

    public deleteById(id: number): void {
        this.products = this.products.filter(product => product.getId() !== id)
    }

    public getProducts(): Product[] {
        return this.products
    }

    public static getInstance(): ShoppingCart {
        if(!ShoppingCart.instance) ShoppingCart.instance = new ShoppingCart()

        return ShoppingCart.instance
    }
}

function clientApp() {
    const silla = new Product(1, 'Silla de oficina', 10000)
    const mesa = new Product(2, 'Mesa para oficina', 20000)
    const lampara = new Product(3, 'Lampara de oficina', 5000)

    const shoppingCart = ShoppingCart.getInstance()

    // agregamos los productos al carrito
    shoppingCart.add(silla)
    shoppingCart.add(mesa)
    shoppingCart.add(lampara)

    console.log(shoppingCart.getProducts())

    // eliminamos un producto
    shoppingCart.deleteById(mesa.getId())

    console.log(shoppingCart.getProducts())
}

clientApp()

I think this should do it:

class ShoppingCart {
    static instance = undefined;

    constructor() {
        this.products = [];
    }

    getProducts = () => {
        return this.products;
    }

    addProduct = (product) => {
        return this.products.push(product);
    }

    deleteProductById = (id) => {
        return this.products = this.products.filter((product) => product.id !== id);
    }

    static getInstance = () => {
        if (!ShoppingCart.instance) ShoppingCart.instance = new ShoppingCart()
        return ShoppingCart.instance;
    }
}

class Product {
    constructor(id, name, cost) {
        this.id = id;
        this.name = name;
        this.cost = cost;
    }
    getID() {
        return this.id;
    }
    getName() {
        return this.name;
    }
    getCost() {
        return this.cost;
    }
}

const ClientApp = () => {
    const cart = ShoppingCart.getInstance();
    const vasos = new Product(1205, 'paquete de vasos', 12000);
    const zapatos = new Product(2166, 'zapatos - par', 57600)
    console.log(vasos.getName(), vasos.getCost(), vasos.getID());
    // Agregamos productos al carrito. 
    cart.addProduct(vasos);
    console.log('Agregamos vasos al cart', cart.getProducts());

    // confirmamos que el cart es el mismo, aún en otra instancia. 
    const cart2 = ShoppingCart.getInstance();
    cart2.addProduct(zapatos);
    console.log('Probamos que el nuevo cart también tiene productos', cart2.getProducts());

    // Borramos el producto y probamos en ambos carritos. 
    cart.deleteProductById(1205);
    console.log('Eliminamos vasos del cart', cart.getProducts(), cart2.getProducts());
}

ClientApp();
Esta fue mi solucion para el reto, me costo pero lo logre comprender muy bien a la final ```js //Se crea la clase producto con sus atributos y métodos class Product { constructor(id, name, cost) { this.id = id; this.name = name; this.cost = cost; } getId() { return this.id; } getName() { return this.name; } getCost() { return this.cost; } } //Se crea la clase carrito class ShoppingCart { //Se crea su instancia que sea estatica static instance = undefined; constructor() { this.cart = []; } //Se crean sus diferentes metodos getCart() { return this.cart; } add(product) { this.cart.push(product); } deleteById(id) { this.cart = this.cart.filter((prod) => prod.getId() !== id); } //Se crea el metodo que llamara al constructor y retornara la instancia static getInstance() { if (!ShoppingCart.instance) ShoppingCart.instance = new ShoppingCart(); return ShoppingCart.instance; } } function appSingleton() { const product1 = new Product(1, "Cafe", 3000) const product2 = new Product(2, "Atun", 5000) const product3 = new Product(3, "Gelatina", 1500) const cart1 = ShoppingCart.getInstance() const cart2 = ShoppingCart.getInstance() cart1.add(product1) cart1.add(product2) cart1.add(product3) cart1.deleteById(1) console.log(cart1.getCart()); console.log(cart1 === cart2); } appSingleton() ```

Mi solución

class ShoppingCar {
    
    static instance = {};

    constructor(cliente) {
        this.cliente = cliente;
        this.products = [];
    }

    static getInstance(cliente) {
        if(!ShoppingCar.instance[cliente]){
            ShoppingCar.instance[cliente] = new ShoppingCar(cliente);
        }

        return ShoppingCar.instance[cliente];
    }

    add(product) {
        this.products.push(product);
    }

    deleteById(id){
        const index = this.products.findIndex(product => product.id === id);
        if (index !== -1) {
            this.products.splice(index, 1);
        }
    }
}

class Product {
    
    constructor(id,name,cost){
        this.id = id;
        this.name = name;
        this.cost = cost;
    }

    getName() {
        return this.name;
    }

    getCost() {
        return this.cost;
    }

    getId() {
        return this.number;
    }
}

function clientApp() {
    const cliente1 = ShoppingCar.getInstance('cliente1');
    const cliente1copia = ShoppingCar.getInstance('cliente1');
    const cliente2 = ShoppingCar.getInstance('cliente2');

    cliente1.add(new Product(0,'Computadora',1200));
    cliente1.add(new Product(1,'Celular',850));
    cliente1.add(new Product(2,'Cubo Rubik',10));

    cliente1.deleteById(1);

    console.log(cliente1,cliente1copia);


    console.log(
        `cliente1 y cliente1copia son iguales? ${ cliente1 === cliente1copia ? 'yes' : 'no'}`
    );

    console.log(
        `cliente1 y cliente2 son iguales? ${ cliente1 === cliente2 ? 'yes' : 'no'}`
    );
}

clientApp();
Les paso mi implementación de nuevo, porque el editor me falló. ![](https://static.platzi.com/media/user_upload/product-98354531-0281-41bb-b979-86df6970b089.jpg) ![](https://static.platzi.com/media/user_upload/shopingCart-e840fe3a-c3b6-4a40-86e2-a8773202f2e8.jpg) ![](https://static.platzi.com/media/user_upload/clientApp-6be5642d-ea50-4bf8-bfd7-e99bdc410fd6.jpg) Y el resultado: ![](https://static.platzi.com/media/user_upload/image-a2d24fea-dc65-4f15-9a5a-c8c912218543.jpg)

Hola, comparto mi solución, pense primero en usar .findIndex() y luego .splice() para el deleteById, aunque note en los comentarios que la mayoria usaron .filter():

class Product {
    private _id: number;
    private _name: string;
    private _cost: number;

    constructor(id: number, name: string, cost: number) {
        this._id = id;
        this._name = name;
        this._cost = cost;
    }

    get id() {
        return this._id;
    }
    get name() {
        return this._name;
    }
    get cost() {
        return this._cost;
    }
}

class ShoppingCar {
    private static instance: ShoppingCar;
    private _products: Array<Product>;

    private constructor() {
        this._products = [];
    }

    public static getInstance(): ShoppingCar {
        if (!ShoppingCar.instance) {
            ShoppingCar.instance = new ShoppingCar();
        }
        return ShoppingCar.instance;
    }

    get products() {
        return this._products;
    }

    add(product: Product): void {
        this._products.push(product);
    }
    deleteById(id: number): void {
        const index = this._products.findIndex(product => product.id === id);
        if (index !== -1) this._products.splice(index, 1);
        else console.log("producto no encontrado");
    }
}

function clientApp() {
    const shoppingCar = ShoppingCar.getInstance();

    shoppingCar.add(new Product(1, "Collar Dorado", 200));
    shoppingCar.add(new Product(3, "Silla", 250));
    shoppingCar.add(new Product(2, "Vaso", 50));

    console.log(shoppingCar.products);

    shoppingCar.deleteById(1);
    shoppingCar.deleteById(1);

    console.log(shoppingCar.products);

    const shoppingCar2 = ShoppingCar.getInstance();
    console.log(shoppingCar === shoppingCar2);
}

clientApp();

Les dejo como implemente el codigo del reto, espero sus feedback

Class Product

class Product {
    constructor(id, name, cost) {
        this._id = id;
        this._name = name;
        this._cost = cost;
    }
    getName() {
        return this._name;
    }
    getCost() {
        return this._cost;
        }
    getId() {
        return this._id;
    }
}

Class ShoppingCar

class ShoppingCar {
    static instance = undefined

    constructor() {
        this._products = []
    }

    static getInstance() {
        if(!ShoppingCar.instance) {
            ShoppingCar.instance = new ShoppingCar()
        }
        return ShoppingCar.instance
    }

    addProduct(product) {
        this._products.push(product)        
    }
    getProductById(id) {
        return this._products.find(product => product._id === id)
    }
    getProductByName(name) {
        return this._products.filter(product => product._name === name)
    }
    setProduct(newProductList) {
        this._products = newProductList
    }
    deleteProduct(id) {
        const deletedProduct = this.getProductById(id)
        const newProductList = this._products.filter(product => product._id !== id)
        this.setProduct(newProductList)
        return deletedProduct._name
    }
    getAllProduct() {
        return this._products
    }    
}

Cliente App para probar el funcionamiento del codigo

(function clienteApp() {
    const cart = ShoppingCar.getInstance();
    const vasos = new Product(1, "vasos plasticos" , 3)
    const zapatos = new Product(2, "gomas deportivas" , 30)
    const franela = new Product(3, "franela azul" , 25)
    const gorra = new Product(4, "gorra americana" , 10)
    const shorts = new Product(5, "shorts rojos" , 15)    

    cart.addProduct(vasos)
    cart.addProduct(zapatos)
    cart.addProduct(franela)
    cart.addProduct(gorra)
    /* Validamos que hay productos en el carrito */
    console.log(cart.getAllProduct);
    
    /* Instanciamos un segundo carrito y validamos que ya tiene productos*/
    const cart2 = ShoppingCar.getInstance();
    console.log(cart2.getAllProduct);
    /* Le agregamos un producto */
    cart2.addProduct(shorts);
    console.log(cart2.getAllProduct())
    /* Eliminamos un producto */
    console.log('Eliminamos exitosament el producto', cart.deleteProduct(2))

    /* Validamos que se elimino en ambos carritos */    
    console.log(cart.getAllProduct(),)
    console.log(cart2.getAllProduct())
})()
`class ShoppingCar {  private static instance: ShoppingCar;  public products: Product[] = [];` `  private constructor() { }` `  static getInstance(): ShoppingCar {    if(!ShoppingCar.instance) {      ShoppingCar.instance = new ShoppingCar();    }` `    return ShoppingCar.instance;  }` `  public add(``product``: Product): void {    this.products.push(``product``);  }` `  public deleteById(``id``: number): void {    this.products = this.products.filter(``product`` => ``product``.getId() !== ``id``);  }}` `class Product{  constructor(private ``id``: number, private ``name``: string, private ``cost``: number) { }` `  public getId(): number {    return this.id;  }` `  public getName(): string {    return this.name;  }` `  public getCost(): number {    return this.cost;  }}` `function app() {  const shoppingCar = ShoppingCar.getInstance();  const product = new Product(1, 'TV', 1000);  const product2 = new Product(2, 'PC', 2000);  const product3 = new Product(3, 'Phone', 3000);  shoppingCar.add(product);  shoppingCar.add(product2);  shoppingCar.add(product3);` `  const shoppingCar2 = ShoppingCar.getInstance();  const product4 = new Product(4, 'video game', 4000);  shoppingCar2.add(product4);` `  console.log(shoppingCar.products);` `  shoppingCar.deleteById(2);` `  console.log(shoppingCar.products);  console.log(shoppingCar2.products);}` `app();`
` ```javascript ` class ShoppingCar {  private static instance: ShoppingCar;  public products: Product\[] = \[];   private constructor() { }   static getInstance(): ShoppingCar {    if(!ShoppingCar.instance) {      ShoppingCar.instance = new ShoppingCar();    }     return ShoppingCar.instance;  }   public add(*product*: Product): void {    this.products.push(*product*);  }   public deleteById(*id*: number): void {    this.products = this.products.filter(*product* => *product*.getId() !== *id*);  }} class Product{  constructor(private *id*: number, private *name*: string, private *cost*: number) { }   public getId(): number {    return this.id;  }   public getName(): string {    return this.name;  }   public getCost(): number {    return this.cost;  }} function app() {  const shoppingCar = ShoppingCar.getInstance();  const product = new Product(1, 'TV', 1000);  const product2 = new Product(2, 'PC', 2000);  const product3 = new Product(3, 'Phone', 3000);  shoppingCar.add(product);  shoppingCar.add(product2);  shoppingCar.add(product3);   const shoppingCar2 = ShoppingCar.getInstance();  const product4 = new Product(4, 'video game', 4000);  shoppingCar2.add(product4);   console.log(shoppingCar.products);   shoppingCar.deleteById(2);   console.log(shoppingCar.products);  console.log(shoppingCar2.products);} app(); ` ``` `
```js class ShoppingCar { private static instance: ShoppingCar; public products: Product[] = []; private constructor() { } static getInstance(): ShoppingCar { if(!ShoppingCar.instance) { ShoppingCar.instance = new ShoppingCar(); } return ShoppingCar.instance; } public add(product: Product): void { this.products.push(product); } public deleteById(id: number): void { this.products = this.products.filter(product => product.getId() !== id); } } class Product{ constructor(private id: number, private name: string, private cost: number) { } public getId(): number { return this.id; } public getName(): string { return this.name; } public getCost(): number { return this.cost; } } function app() { const shoppingCar = ShoppingCar.getInstance(); const product = new Product(1, 'TV', 1000); const product2 = new Product(2, 'PC', 2000); const product3 = new Product(3, 'Phone', 3000); shoppingCar.add(product); shoppingCar.add(product2); shoppingCar.add(product3); const shoppingCar2 = ShoppingCar.getInstance(); const product4 = new Product(4, 'video game', 4000); shoppingCar2.add(product4); console.log(shoppingCar.products); shoppingCar.deleteById(2); console.log(shoppingCar.products); console.log(shoppingCar2.products); } app(); ```class ShoppingCar {  private static instance: ShoppingCar;  public products: Product\[] = \[];   private constructor() { }   static getInstance(): ShoppingCar {    if(!ShoppingCar.instance) {      ShoppingCar.instance = new ShoppingCar();    }     return ShoppingCar.instance;  }   public add(*product*: Product): void {    this.products.push(*product*);  }   public deleteById(*id*: number): void {    this.products = this.products.filter(*product* => *product*.getId() !== *id*);  }} class Product{  constructor(private *id*: number, private *name*: string, private *cost*: number) { }   public getId(): number {    return this.id;  }   public getName(): string {    return this.name;  }   public getCost(): number {    return this.cost;  }} function app() {  const shoppingCar = ShoppingCar.getInstance();  const product = new Product(1, 'TV', 1000);  const product2 = new Product(2, 'PC', 2000);  const product3 = new Product(3, 'Phone', 3000);  shoppingCar.add(product);  shoppingCar.add(product2);  shoppingCar.add(product3);   const shoppingCar2 = ShoppingCar.getInstance();  const product4 = new Product(4, 'video game', 4000);  shoppingCar2.add(product4);   console.log(shoppingCar.products);   shoppingCar.deleteById(2);   console.log(shoppingCar.products);  console.log(shoppingCar2.products);} app();

Buenas! Dejo mi implementación en Python

class Product:

    def __init__(self, id, name, cost):
        self._id = id
        self._name = name
        self._cost = cost

    def get_name(self):
        return self._name

    def get_cost(self):
        return self._cost
    
    def get_id(self):
        return self._id

class ShoppingCar:

    _instance = None
    _products = []

    def __new__(cls):
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def add_product(self, product):
        self._products.append(product)

    def delete_by_id(self,id):
        for elemento in self._products:
            if elemento['id'] == id:
                self._products.remove(elemento)
    def show_products(self):
        return self._products

    @staticmethod
    def get_instance():
        return ShoppingCar()

class ClientApp:
    def __init__(self, id):
        self.id = id
        self.shopping_car = ShoppingCar.get_instance()

client = ClientApp(1)
client_2 = ClientApp(2)
print(client.shopping_car , client_2.shopping_car, client.shopping_car == client_2.shopping_car) # True
client.shopping_car.add_product(Product(1,'chocolate',22))

print(client.shopping_car == client_2.shopping_car, '#######')

Haciendo privada las propiedades de Product, es la forma en la que se me ocurrió después acceder a ellas mediante ShoppingCar.

class ShoppingCar{
    static #instanceSC = undefined;
    #products = [];
    
    addProduct(product){
        this.#products.push(product);
    }
    getProducts(){
        return this.#products;
    }

    deleteById(id){
        for (let n = 0; n < this.#products.length; n++) {
            if (this.#products[n].id === id) {
                this.#products.splice(n, 1);
                break; // Si los IDs son únicos, puedes salir del bucle una vez encontrado
            }
        }
        return this.#products;
    }
    static getInstance(){
        if(!ShoppingCar.#instanceSC){
            ShoppingCar.#instanceSC = new ShoppingCar();
        }
        return ShoppingCar.#instanceSC;
    }
}

class Product{
    #id;
    #name;
    #cost;

    constructor(id, name, cost) {
        this.#id = id;
        this.#name = name;
        this.#cost = cost;
    }

    getName() {
        return this.#name;
    }

    getCost() {
        return this.#cost;
    }

    getId() {
        return this.#id;
    }
}

const myShoppingCart = ShoppingCar.getInstance();
const myProduct = new Product(1, 'kevin', 100000);

myShoppingCart.addProduct(myProduct);

const products = myShoppingCart.getProducts();
products.forEach(product => {
    console.log(`ID: ${product.getId()}, Name: ${product.getName()}, Cost: ${product.getCost()}`);
});
I just want to share my solution in TS: ```ts class ShoppingCart { private static instance: ShoppingCart; private cart: Product[] = []; private constructor() {} static getInstance(): ShoppingCart { if (!ShoppingCart.instance) { ShoppingCart.instance = new ShoppingCart(); } return ShoppingCart.instance; } public getCart(): Product[] { return this.cart; } public addProduct(product: Product): void { this.cart.push(product); } public deleteById(id: number): void { let indexProduct = this.cart.findIndex((item) => item.getId() == id); this.cart.splice(indexProduct, 1); } } class Product { private id: number; private name: string; private cost: number; public constructor(id: number, name: string, cost: number) { this.id = id; this.name = name; this.cost = cost; } public getId(): number { return this.id; } public getName(): string { return this.name; } public getCost(): number { return this.cost; } } (() => { const cart = ShoppingCart.getInstance(); const cart2 = ShoppingCart.getInstance(); const p1 = new Product(1, "camara", 500); const p2 = new Product(2, "cama", 1500); const p3 = new Product(3, "cojin", 20); cart.addProduct(p1); cart.addProduct(p2); cart.addProduct(p3); console.log(cart.getCart()); cart.deleteById(2); console.log(cart.getCart()); // Verify the instance is the same in both carts console.log(cart === cart2); console.log(cart.getCart()); console.log(cart2.getCart()); })(); ```class ShoppingCart {  private static instance: ShoppingCart;  private cart: Product\[] = \[];   private constructor() {}   static getInstance(): ShoppingCart {    if (!ShoppingCart.instance) {      ShoppingCart.instance = new ShoppingCart();    }    return ShoppingCart.instance;  }  public getCart(): Product\[] {    return this.cart;  }  public addProduct(product: Product): void {    this.cart.push(product);  }  public deleteById(id: number): void {    let indexProduct = this.cart.findIndex((item) => item.getId() == id);    this.cart.splice(indexProduct, 1);  }} class Product {  private id: number;  private name: string;  private cost: number;   public constructor(id: number, name: string, cost: number) {    this.id = id;    this.name = name;    this.cost = cost;  }  public getId(): number {    return this.id;  }  public getName(): string {    return this.name;  }  public getCost(): number {    return this.cost;  }} (() => {  const cart = ShoppingCart.getInstance();  const cart2 = ShoppingCart.getInstance();  const p1 = new Product(1, "camara", 500);  const p2 = new Product(2, "cama", 1500);  const p3 = new Product(3, "cojin", 20);   cart.addProduct(p1);  cart.addProduct(p2);  cart.addProduct(p3);   console.log(cart.getCart());   cart.deleteById(2);   console.log(cart.getCart());  // Verify the instance is the same in both carts  console.log(cart === cart2);  console.log(cart.getCart());  console.log(cart2.getCart());})();

Mi sulocion Ts

class Product {
    private id: number;
    private name: string;
    private cost: number;

    constructor(id: number, name: string, cost: number) {
        this.id = id;
        this.name = name;
        this.cost = cost;
    }

    getid(): number {
        return this.id;
    };

    getName(): string {
        return this.name;
    };

    getCost(): number {
        return this.cost;
    };
};

class ShoppingCar {
    private static instance: ShoppingCar;
    private products: Product[];

    private constructor() {
        this.products = [];
    }

    static getInstance(): ShoppingCar {
        if (!ShoppingCar.instance) {
            ShoppingCar.instance = new ShoppingCar;
        }
        return ShoppingCar.instance;
    }

    addProduct(...product: Product[]) {
        this.products.push(...product)
    }

    getProducts(): Product[] {
        return this.products;
    }

    deleteById(id: number) {
        return this.products = this.products.filter(elem => elem.getid() !== id);
    }

}

// implementacion 
// crear una unica instancia de shopping car
const car = ShoppingCar.getInstance();
const car2 = ShoppingCar.getInstance();

// crear 2 products para poblar
let product1 = new Product(1, 'amp', 1500);
let product2 = new Product(2, 'guitar', 1700);

car.addProduct(product1, product2)

// comprobaciones en consola
console.log(`shold be true, ${car === car2}`);
console.log(car.getProducts());




```ts // Product class Product { private id: number; private name: string; private cost: number; constructor(id: number, name: string, cost: number) { this.id = id; this.name = name; this.cost = cost; } // obtener nombre public getName(): string { return this.name; } // obtener costo public getCost(): number { return this.cost; } // obtener ID public getId(): number { return this.id; } } // ShoppingCar (singleton) class ShoppingCar { private static instance: ShoppingCar; private list_products: Product[] = []; // constructor privado private constructor() {} // agregar producto public add(product: Product): void { const existingProduct: number = this.list_products.findIndex((p) => { return p.getId() === product.getId(); }); if (existingProduct === -1) this.list_products.push(product); else console.warn(`El producto ${product.getName()} ya esta en la lista.`); } // eliminar producto por ID public deleteById(id: number): void { const i: number = this.list_products.findIndex( (product: Product): boolean => product.getId() === id, ); if (i !== -1) this.list_products.splice(i, 1); else console.error(`Producto con ID ${id} no encontrado`); } // obtener lista de productos public getProducts(): Product[] { return [...this.list_products]; // Devuelve una copia para proteger la encapsulación } // método estatico para obtener la instancia única static getInstance(): ShoppingCar { if (!ShoppingCar.instance) ShoppingCar.instance = new ShoppingCar(); return ShoppingCar.instance; } } // carro de productos const shopping_car: ShoppingCar = ShoppingCar.getInstance(); // productos const productOne = new Product(1, "monitor", 1500), productTwo = new Product(2, "audifonos", 346), productThree = new Product(3, "gorra", 105); // agregamos al carro shopping_car.add(productOne); shopping_car.add(productTwo); shopping_car.add(productThree); shopping_car.add(productTwo); // da error en consola shopping_car.deleteById(53); console.log(shopping_car.getProducts()); shopping_car.deleteById(2); console.log(shopping_car.getProducts()); // son de la misma instancia? const shopping_car_two = ShoppingCar.getInstance(); console.log(shopping_car === shopping_car_two); ```
Mi solucion aqui ```js class ShoppingCart { private static instance: ShoppingCart; private products: Product[]; constructor() {} static getInstance() { if (this.instance === null) { this.instance = new ShoppingCart(); } return this.instance; } add(product: Product) { this.products.push(product); } deleteById(id: number) { this.products = this.products.filter((product) => product.getId() !== id) } } class Product { private id: number; private name: string; private cost: number; constructor(id: number, name: string, cost: number) { this.id = id; this.name = name; this.cost = cost; } getName() { return this.name; } getCost() { return this.cost; } getId() { return this.id; } } ```

Mi código de TS 👍:

class Product {
    private id: number;
    private name: string;
    private price: number;

    constructor(id: number, name: string, price: number) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    setId(id: number) {
        this.id = id;
    }

    setName(name: string) {
        this.name = name;
    }

    setPrice(price: number) {
        this.price = price;
    }

    getId() {
        return this.id;
    }

    getName() {
        return this.name;
    }

    getPrice() {
        return this.price;
    }
}

/* 
    We create our singleton class, the idea behind having one, is that therere never 2 of these.
    Just one per app or client
*/
class ShoppingCart {
    private static instance: ShoppingCart;
    private products: Product[] = [];

    private constructor() {}

    static getInstance() {
        if(!ShoppingCart.instance) {
            ShoppingCart.instance = new ShoppingCart();
        }
        return ShoppingCart.instance;
    }

    setCart(products: Product[]) {
        this.products = products;
    }

    getCart() {
        return this.products;
    }

    add(product: Product) {
        this.products.push(product);
    }

    addGroup(products: Product[]) {
        // pushes each element of the array 
        products.forEach(prod => this.products.push(prod));
    }

    remove(id: number) {
        this.products = this.products.filter((product) => product.getId() !== id);
    }
}

function app() {
    const cart1 = ShoppingCart.getInstance();
    const cart2 = ShoppingCart.getInstance();

    const products: Product[] = [
        new Product(1, "Dónde", 100),
        new Product(2, "está", 200),
        new Product(3, "Dios", 300)
    ];

    cart1.addGroup(products);
    cart1.remove(1);

    // We never added anything to cart2, but it has the same instance as cart1,
    // so both are equals
    console.log(cart1 === cart2); // true
}

app();
Me gusto mucho esta explicación de Singleton, tengo un rato revisando patrones de diseño y no les estaba agarrando el hilo, hasta ahora. Gracias!!!
Comparto por aquí mi implementación del Singleton del Shopping Car ✨~ ![](https://i.imgur.com/Xlwd1Sk.png)
Aqui les dejo mi codigo del reto que puso el profe :) Si ven algun error o tienen alguna sugerencia para mejorar el codigo, diganmelo 👀👌 ```js class Product{ constructor(name, id, price){ this.name = name this.id = id this.price = price } } class ShoppingCart{ static instance = undefined constructor() { if(ShoppingCart.instance) return ShoppingCart.instance() this.object = [] ShoppingCart.instance = this } static getInstance(){ if(!ShoppingCart.instance) ShoppingCart.instance = new ShoppingCart() return ShoppingCart.instance } addToCart(product) { this.object.push(product) } getTotal() { return this.object.reduce((total, product) => total + product.price, 0) } } const cart = ShoppingCart.getInstance() const laptop = new Product("Laptop", 865, 1800) const smartphone = new Product("Smartphone", 555, 650) cart.addToCart(laptop) cart.addToCart(smartphone) console.log("El precio total de los productos es => ", cart.getTotal()) ```
Recuerdo haber utilizado en Angular este patrón, creo en la inyección de servicios.
Por acá mi solución en Typescript: ```js class Product { constructor( private id: number, private name: string, private cost: number ) {} getName(): string { return this.name; } getCost(): number { return this.cost; } getId(): number { return this.id; } } class ShoppingCar { private static instance: ShoppingCar; public products: Product[] = []; private constructor() {} static getInstance() { if(!this.instance) { this.instance = new ShoppingCar(); } return this.instance; } addProduct(product: Product): void { this.products.push(product); } deleteById(id: number): void { const index = this.products.findIndex((product) => product.getId() === id); this.products.splice(index, 1); } } const car1 = ShoppingCar.getInstance(); const car2 = ShoppingCar.getInstance(); const product1 = new Product(1, "carrito", 20); const product2 = new Product(2, "juguete", 30); const product3 = new Product(3, "arepa", 5); car1.addProduct(product2); car1.addProduct(product3); car1.addProduct(product1); car2.deleteById(2); console.log(car2.products); ```class Product {    constructor(        private id: number,        private name: string,        private cost: number    ) {}     getName(): string {        return this.name;    }     getCost(): number {        return this.cost;    }     getId(): number {        return this.id;    }} class ShoppingCar {    private static instance: ShoppingCar;    public products: Product\[] = \[];     private constructor() {}     static getInstance() {        if(!this.instance) {            this.instance = new ShoppingCar();        }         return this.instance;    }     addProduct(product: Product): void {        this.products.push(product);    }     deleteById(id: number): void {        const index = this.products.findIndex((product) => product.getId() === id);        this.products.splice(index, 1);    }} const car1 = ShoppingCar.getInstance();const car2 = ShoppingCar.getInstance(); const product1 = new Product(1, "carrito", 20);const product2 = new Product(2, "juguete", 30);const product3 = new Product(3, "arepa", 5); car1.addProduct(product2);car1.addProduct(product3);car1.addProduct(product1); car2.deleteById(2); console.log(car2.products);
Puntos que considero el mejor uso en mi experiencia: 1.- Manejo de estado único por usuario, es muy útil cuando es un estado único a nivel de usuario, no a nivel de aplicación. 2.- Manejo de objetos que sabemos que tienen una cantidad fija, ejemplo un juego de cartas que juegan si o si solo 2 jugadores.
**Apuntes:** **Cosas cool** * Certeza de que solo existirá una instancia de una clase. * Un solo punto de acceso global a dicha instancia. * La instancia es inicializada solo cuando se requiere la primera vez. **Cosas no tan cool** * **Vulnera el principio de responsabilidad única.** El patrón resuelve dos problemas al mismo tiempo. * **Complejidad incrementada en ambiente de múltiples hilos de ejecución** ¿Cómo hacer que muchos hilos no creen un objeto singleton múltiples veces? * **Complejidad a la hora de crear pruebas unitarias** debido al uso de elementos estáticos
Gran clase pero me hubiese gustado que el profesor muestre paso a paso como desarrollar este reto con datos reales por ejemplo, de manera a comprender mucho mejor.
¿Cuándo creo que puede funcionar Singleton? Creo que puede ser un diseño efectivo para control de estados como comenta Daniel y seguramente cuando se necesitan conexiones únicas a algún recurso. Para cualquier caso en el que realmente sea importante el tema de tener una sola 'llave' de apertura de algún recurso.
`class Product {` ` constructor(id, name, cost) {` ` this.id = id;` ` this.name = name;` ` this.cost = cost;` ` }` ` getName() {` ` return this.name;` ` }` ` getCost() {` ` return this.cost;` ` }` ` getId() {` ` return this.id;` ` }` `}` `class ShoppingCar {` ` constructor() {` ` if (ShoppingCar.instance) {` ` return ShoppingCar.instance;` ` }` ` this.products = [];` ` ShoppingCar.instance = this;` ` }` ` add(product) {` ` this.products.push(product);` ` }` ` deleteById(id) {` ` this.products = this.products.filter(product => product.id !== id);` ` }` ` getInstance() {` ` return ShoppingCar.instance;` ` }` `}` `// Uso del patrón Singleton` `const shoppingCar1 = new ShoppingCar();` `const shoppingCar2 = new ShoppingCar();` `console.log(shoppingCar1 === shoppingCar2); // true` `// Añadiendo productos al carrito` `const product1 = new Product(1, "Producto 1", 100);` `const product2 = new Product(2, "Producto 2", 200);` `shoppingCar1.add(product1);` `shoppingCar2.add(product2);` `console.log(shoppingCar1.products); // [Product { id: 1, name: 'Producto 1', cost: 100 }, Product { id: 2, name: 'Producto 2', cost: 200 }]` `console.log(shoppingCar2.products); // [Product { id: 1, name: 'Producto 1', cost: 100 }, Product { id: 2, name: 'Producto 2', cost: 200 }]`
```js class Singelton { static instance = undefined; #listProducts = []; constructor(versions) { this.version = this.version }; static getInstance(version) { if (!Singelton.instance) { Singelton.instance = new Singelton(version); } return Singelton.instance } addProduct(product) { this.#listProducts.push(product) } removeProduct(product) { this.#listProducts.splice(listProducts.indexOf(product), 1) } showProducts() { this.#listProducts.forEach(e => { console.log(e) }) } } function appSingelton(){ const singelton1 = Singelton.getInstance("1.0") const singelton2 = Singelton.getInstance("2.0") const sigleton3 = Singelton.getInstance("3.0") sigleton3.addProduct("Producto 1") sigleton3.addProduct("Producto 2") sigleton3.addProduct("Producto 3") sigleton3.showProducts() singelton2.showProducts() console.log(singelton1 === singelton2) } appSingelton() ```class Singelton { static instance = undefined; \#listProducts = \[]; constructor(versions) { this.version = this.version }; static getInstance(version) { if (!Singelton.instance) { Singelton.instance = new Singelton(version); } return Singelton.instance } addProduct(product) { this.#listProducts.push(product) } removeProduct(product) { this.#listProducts.splice(listProducts.indexOf(product), 1) } showProducts() { this.#listProducts.forEach(e => { console.log(e) }) } } function appSingelton(){ const singelton1 = Singelton.getInstance("1.0") const singelton2 = Singelton.getInstance("2.0") const sigleton3 = Singelton.getInstance("3.0") sigleton3.addProduct("Producto 1") sigleton3.addProduct("Producto 2") sigleton3.addProduct("Producto 3") sigleton3.showProducts() singelton2.showProducts() console.log(singelton1 === singelton2) } appSingelton()
aporte `class products { constructor({id, name , cost}){ this._id = id, this._name = name, this._cost = cost } get id(){ return this._id; } get name(){ return this._name; } get cost(){ return this._cost; } }const carro = new products({id:0, name:"carro", cost:200})const moto = new products({id:1, name:"motos", cost:300})const avion = new products({id:1, name:"motos", cost:300})console.log(carro)class ShoppingCart { static instance = undefined; constructor (client){ this._client = client this._product = [] } static getInstance (client){ if (!ShoppingCart.instance){ ShoppingCart.instance = new ShoppingCart(client) } return ShoppingCart.instance } set addProduct(products){ this._product.push(products) } set removeProduct(products){ this._product= this._product.remove(e => console.log) } set deletProduct(productId){ this._product = this._product.filter(product => !(product.id == productId)) }}const client1 = ShoppingCart.getInstance("cliente 1")const client2 = ShoppingCart.getInstance("cliente 2")` `client1.addProduct = carroclient1.addProduct = motoclient1.deletProduct = 0` `console.log(client1)`
Dejo la implementacion en python, en este caso haciendo uso del parametro ```metaclass``` , que a lo que investige esta metaclase define el comportameito de la clase , de modo que al sobreescribir el metodo \_\_call\_\_ en esta, se sobreescribe el comportamiento cuando llamas o invocas a la clase, y es ahi donde validamos la creacion de la unica instancia. ```js class Product: def __init__(self, _id: int, name: str, cost: float): self._id = _id self.name = name self.cost = cost def get_id(self): return self._id class ShoppingCarMeta(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: instance = super().__call__(*args, **kwargs) cls._instances[cls] = instance return cls._instances[cls] class ShoppingCar(metaclass=ShoppingCarMeta): products: list[Product] = [] def add_product(self, product: Product): self.products.append(product) def delete_product(self, id_product: int): self.products = list(filter(lambda p: p.get_id() != id_product, self.products)) def show_products(self): return [product.name for product in self.products] if __name__ == '__main__': my_car = ShoppingCar() my_car.add_product(ball) my_car.add_product(shirt) print(my_car.show_products()) my_car2 = ShoppingCar() my_car2.add_product(notebook) print(my_car2.show_products()) my_car.delete_product(4) print(my_car2.show_products()) ```
Como reto personal, decidí implementar este patrón con Swift. Aquí les dejo el código a los curiosos: ```js import Foundation class Singleton { static private var instance: Singleton? private let id: UUID private init() { self.id = UUID() } static public func getInstance() -> Singleton { if Singleton.instance == nil { Singleton.instance = Singleton() } return Singleton.instance! } func print() { print("Singleton id is: \(self.id)") } } ```
Como reto personal, decidí implementar este patrón con Swift. Aquí les dejo el código a los curiosos: ```txt import Foundation class Singleton { static private var instance: Singleton? private let id: UUID private init() { self.id = UUID() } static public func getInstance() -> Singleton { if Singleton.instance == nil { Singleton.instance = Singleton() } return Singleton.instance! } func printId() { print("Singleton id is: \(self.id)") } } ```
Va mi solución al reto en JS: ```js class Product { constructor({ id, name, cost }) { this.#objectSetup({ id, name, cost }); } #privateData = { _id: 0, _name: "", _cost: 0, }; #objectSetup({ id, name, cost }) { if (!id || !name || !cost) { throw new Error("Missing data."); } this.#privateData._id = id; this.#privateData._name = name; this.#privateData._cost = cost; return { id: this.#privateData._id, name: this.#privateData._name, cost: this.#privateData._cost, }; } get id() { return this.#privateData._id; } get name() { return this.#privateData._name; } get cost() { return this.#privateData._cost; } get product() { return { id: this.#privateData._id, name: this.#privateData._name, cost: this.#privateData._cost, }; } } ``````js class ShoppingCart { static #instance = undefined; constructor() {} #privateProducts = []; static getInstance() { if (!ShoppingCart.#instance) { const newInstance = new ShoppingCart(); ShoppingCart.#instance = newInstance; } return ShoppingCart.#instance; } addProduct(product) { if (product instanceof Product) { this.#privateProducts.push(product); return product; } else { throw new Error("Not a valid product."); } } deleteById(id) { if (typeof id === "number") { const productIndex = this.#privateProducts.findIndex( (product) => product.id === id ); if (!productIndex) { throw new Error("Product not found to delete."); } else { const deletedProduct = this.#privateProducts.splice(productIndex, 1); return deletedProduct; } } } get products() { return this.#privateProducts; } } ```
Mi implementacion al reto. Entendi mucho como funcionan las relaciones con las clases. ```js class ShoppingCart{ static instance = undefined; static products = undefined; constructor() { ShoppingCart.products = [] } static createShoppingCart() { if(!this.instance) { this.instance = new ShoppingCart(); } return this.instance; } addProduct(product){ ShoppingCart.products.push(product) } deleteById(ID = Number){ const index = ShoppingCart.products.findIndex(product=> product.id === ID) if(index != -1){ ShoppingCart.products.splice(index, 1); return `Deleted product` } else{return 'Product not Found';} } getInstance(){ return ShoppingCart.instance; } getProducts() { return ShoppingCart.products; } } class Product{ static name = String; static id = Number; static cost= Number; constructor(ident, costo, nombre) { this.name = nombre; this.id = ident; this.cost = costo; this.exportProduct(this.name, this.id, this.cost); } exportProduct(name, id, cost) { const producto = {name, id, cost} return producto } getName(){ return this.name; } getCost(){ return this.cost; } getId(){ return this.id; } } //creando las instancias const laptop1 = new Product(377, 250, 'Laptop HP') const laptop2 = new Product(336, 450, 'Laptop asus') const laptop3 = new Product(535, 250, 'Laptop Razer') const carrito = ShoppingCart.createShoppingCart() carrito.addProduct(laptop1) carrito.addProduct(laptop2) carrito.addProduct(laptop3) carrito.deleteById(377) console.log(carrito.getProducts()); ```class ShoppingCart{    static instance = undefined;    static products = undefined;     constructor()    {        ShoppingCart.products = \[]    }    static createShoppingCart()    {        if(!this.instance)        {            this.instance = new ShoppingCart();        }        return this.instance;    }    addProduct(product){        ShoppingCart.products.push(product)    }     deleteById(ID = Number){        const index = ShoppingCart.products.findIndex(product=> product.id === ID)        if(index != -1){            ShoppingCart.products.splice(index, 1);            return `Deleted product`        }        else{return 'Product not Found';}    }     getInstance(){        return ShoppingCart.instance;    }    getProducts()    {        return ShoppingCart.products;    }} class Product{     static name = String;    static id = Number;    static cost= Number;     constructor(ident, costo, nombre)    {        this.name = nombre;        this.id = ident;        this.cost = costo;         this.exportProduct(this.name, this.id, this.cost);    }     exportProduct(name, id, cost)    {        const producto = {name, id, cost}        return producto    }     getName(){        return this.name;    }    getCost(){        return this.cost;    }    getId(){        return this.id;    }}//creando las instancias const laptop1 = new Product(377, 250, 'Laptop HP')const laptop2 = new Product(336, 450, 'Laptop asus')const laptop3 = new Product(535, 250, 'Laptop Razer') const carrito = ShoppingCart.createShoppingCart()carrito.addProduct(laptop1)carrito.addProduct(laptop2)carrito.addProduct(laptop3)carrito.deleteById(377)console.log(carrito.getProducts());
Justo, termine de hacer el codigo y realmente aprendí mucho en la practica : class Product {   private id: number;   private name: string;   private cost: number;    constructor(id: number, name:string, cost:number){      this.id = id;      this.cost = cost;      this.name = name;   }    getName():string{      return this.name   }    getCost():number{      return this.cost   }    getId():number{      return this.id   }} class ShoopingCar {    private static instance: ShoopingCar;    private products: Array\<Product>;     private constructor(){}     add(product:Product){       this.products.push(product);    }     deletedById(id:number){       this.products.splice(id, 1);    }     static getInstance(): ShoopingCar{        if(!ShoopingCar.instance){            ShoopingCar.instance = new ShoopingCar();        }        return ShoopingCar.instance    } } const car1 = ShoopingCar.getInstance();const car2 = ShoopingCar.getInstance(); console.log(car1 === car2);
Mi solución al reto. ```js class Product { constructor(id, name, cost) { this.id = id; this.name = name; this.cost = cost; } getName() { return this.name; } getCost() { return this.cost; } getId() { return this.id; } } class ShoppingCart { static instance = undefined; constructor() { this.products = []; } add(product) { this.products.push(product); } deleteById(id) { this.products = this.products.filter((value) => value.getId() !== id); } static getInstance() { if(!ShoppingCart.instance) { ShoppingCart.instance = new ShoppingCart(); } return ShoppingCart.instance; } } function app() { const shoppingCart1 = ShoppingCart.getInstance(); const shoppingCart2 = ShoppingCart.getInstance(); const shoppingCart3 = ShoppingCart.getInstance(); const product1 = new Product(10, "Café", 20.0); const product2 = new Product(2, "Laptop", 8600.0); shoppingCart1.add(product1); shoppingCart2.add(product2); console.log(shoppingCart1, shoppingCart2, shoppingCart3); } app(); ```
```js // Class using the singleton pattern class ShoppingCar { private static instance: ShoppingCar; private products: Array<Product> = []; private constructor () { } public static getInstance(): ShoppingCar { if (!ShoppingCar.instance) { ShoppingCar.instance = new ShoppingCar(); } return ShoppingCar.instance; } public add(product: Product) { this.products.push(product); } public deleteById(id: number) { const index = this.products.findIndex(product => product.getGetId() === id); if (index !== -1) { this.products.splice(index, 1); } else { console.log(`Product with id ${id} not found.`); } } } // Normal Class class Product { private id: number; private name: string; private cost: number; constructor (id: number, name: string, cost: number) { this.id = id; this.name = name; this.cost = cost; } public getName () { return this.name; } public getCost () { return this.cost; } public getGetId () { return this.id; } } // Examples let cart1 = ShoppingCar.getInstance(); let cart2 = ShoppingCar.getInstance(); let isSingleton12 = cart1 === cart2; console.log(`Cart1 and Cart2 are references of the same object? : ${isSingleton12}`); let cart3 = ShoppingCar.getInstance(); let cart4 = ShoppingCar.getInstance(); let isSingleton34 = cart3 === cart4; cart4.add(new Product(1, "Aguacate", 85)); cart4.add(new Product(5, "Lechoza", 115)); cart4.add(new Product(29, "Chinola", 43)); console.log(`Cart3 and Cart4 are references of the same object? : ${isSingleton34}`); cart3.deleteById(1); console.log(`After removing one element from just Cart3... are Cart3 and Cart4 still references of the same object? : ${isSingleton34}`); console.log(`Are Cart1, Cart2, Cart3 and Cart4 references of the same object? : ${isSingleton12 && isSingleton34}`); ```// Class using the singleton patternclass ShoppingCar {     private static instance: ShoppingCar;    private products: Array\<Product> = \[];     private constructor () { }     public static getInstance(): ShoppingCar {        if (!ShoppingCar.instance) {            ShoppingCar.instance = new ShoppingCar();        }        return ShoppingCar.instance;    }     public add(product: Product) {        this.products.push(product);    }     public deleteById(id: number) {        const index = this.products.findIndex(product => product.getGetId() === id);        if (index !== -1) {            this.products.splice(index, 1);        } else {            console.log(`Product with id ${id} not found.`);        }    } } // Normal Classclass Product {    private id: number;    private name: string;    private cost: number;     constructor (id: number, name: string, cost: number) {        this.id = id;        this.name = name;        this.cost = cost;    }     public getName () { return this.name; }    public getCost () { return this.cost; }    public getGetId () { return this.id; }} // Examples let cart1 = ShoppingCar.getInstance();let cart2 = ShoppingCar.getInstance(); let isSingleton12 = cart1 === cart2; console.log(`Cart1 and Cart2 are references of the same object? : ${isSingleton12}`); let cart3 = ShoppingCar.getInstance();let cart4 = ShoppingCar.getInstance(); let isSingleton34 = cart3 === cart4; cart4.add(new Product(1, "Aguacate", 85));cart4.add(new Product(5, "Lechoza", 115));cart4.add(new Product(29, "Chinola", 43)); console.log(`Cart3 and Cart4 are references of the same object? : ${isSingleton34}`); cart3.deleteById(1); console.log(`After removing one element from just Cart3... are Cart3 and Cart4 still references of the same object? : ${isSingleton34}`); console.log(`Are Cart1, Cart2, Cart3 and Cart4 references of the same object? : ${isSingleton12 && isSingleton34}`);
```js class Product { #data static #ALL_PRODUCTS = []; constructor({ id, name, cost }) { this.#data = new Map(); this.#data.set('id', id); this.#data.set('name', name); this.#data.set('cost', cost); this.#data.forEach((value, key) => { if (!value) { throw new Error(`El valor para '${key}' no puede estar vacío.`); } }); const obj = {}; this.#data.forEach((value, key) => { obj[key] = value; }); Product.#ALL_PRODUCTS.push(obj); } getName() { return this.#data.get('name'); } getCost() { return this.#data.get('cost'); } getId() { return this.#data.get('id'); } static getProducts() { return Product.#ALL_PRODUCTS } } const coke = new Product({id: 235463 , name: 'Coke' , cost: 50.000 }) const apple = new Product({id: 245641, name: 'Apple' , cost: 80.000 }) const banana = new Product({id: 34354132 , name: 'Banana' , cost: 20.000 }) const coconut = new Product({id: 2424545 , name: 'Coconut' , cost: 10.000 }) const meat = new Product({id: 25452 , name: 'Meat' , cost: 30.000 }) const pineapple = new Product({id: 2452 , name: 'Pineapple' , cost: 980.000 }) class ShoppingCar { #productsAvailable = Product.getProducts() #userId static #USER_CARS = new Map(); constructor(userId) { this.#userId = userId this.productsSelect = [] } static newUser(userId) { if (!ShoppingCar.#USER_CARS.has(userId)) { const newCar = new ShoppingCar(userId); ShoppingCar.#USER_CARS.set(userId, newCar); return newCar; } else { return ShoppingCar.#USER_CARS.get(userId); } } #addProduct(type, product) { this.#productsAvailable.forEach((element, index) => { if (element[type] === product) { this.productsSelect.push(this.#productsAvailable.splice(index, 1)[0]) } }) } addProductByName(product) { this.#addProduct('name', product); } addProductById(product) { this.#addProduct('id', product); } #deleteProduct(type, product){ this.productsSelect.forEach((element, index) => { if (element[type] === product) { this.#productsAvailable.push(this.productsSelect.splice(index, 1)[0]) } }) } deleteProductByName(product) { this.#deleteProduct('name', product) } deleteProductById(product) { this.#deleteProduct('id', product) } } const user1 = ShoppingCar.newUser('112424254') const user2 = ShoppingCar.newUser('36') const user3 = ShoppingCar.newUser('112424254') user1.addProductByName('Coke') user1.addProductByName('Meat') user1.addProductById(2452) user1.deleteProductById(2452) console.log(user1) ```GG
Les dejo mi ejercicio en TypeScript: ```js interface IProduct { id: number; name: string; cost: number; } class Product { private product: IProduct = { id: 0, name: '', cost: 0 } constructor( product: IProduct){ this.product = product } getName(): string { return this.product.name; } getCost(): number { return this.product.cost; } getId(): number { return this.product.id; } } class ShoppingCar { private static instance: ShoppingCar; private products: Product[] = []; private constructor(){ } static getInstance(): ShoppingCar { if(!ShoppingCar.instance){ ShoppingCar.instance = new ShoppingCar(); } return ShoppingCar.instance } addProduct( product: Product) { this.products.push(product); } deleteById( id: number) { const productExist = !!this.products.find((product) => product.getId() === id); if (productExist) { this.products = this.products.filter((prod) => prod.getId() !== id);; } else { console.log(id," doesnt exist"); } } getShoppingCar(){ return this.products; } } const product1: Product = new Product({ id: 1, name: 'laptop', cost: 1000 }) const product2: Product = new Product({ id: 2, name: 'ps5', cost: 700 }) const product3: Product = new Product({ id: 3, name: 'keyboard', cost: 50 }) const shoppingCar = ShoppingCar.getInstance(); shoppingCar.addProduct(product1); shoppingCar.addProduct(product2); shoppingCar.addProduct(product3); shoppingCar.addProduct(product2); shoppingCar.addProduct(product2); shoppingCar.addProduct(product1); shoppingCar.deleteById(2); console.log(shoppingCar.getShoppingCar()); const shoppingCar2 = ShoppingCar.getInstance(); console.log(shoppingCar2.getShoppingCar()); console.log('Shopping Car 1 y Shopping Car 2 son iguales? ', shoppingCar2 === shoppingCar); ```interface IProduct { id: number; name: string; cost: number;} class Product { private product: IProduct = { id: 0, name: '', cost: 0 } constructor( product: IProduct){ this.product = product } getName(): string { return this.product.name; } getCost(): number { return this.product.cost; } getId(): number { return this.product.id; }} class ShoppingCar { private static instance: ShoppingCar; private products: Product\[] = \[]; private constructor(){ } static getInstance(): ShoppingCar { if(!ShoppingCar.instance){ ShoppingCar.instance = new ShoppingCar(); } return ShoppingCar.instance } addProduct( product: Product) { this.products.push(product); } deleteById( id: number) { const productExist = !!this.products.find((product) => product.getId() === id); if (productExist) { this.products = this.products.filter((prod) => prod.getId() !== id);; } else { console.log(id," doesnt exist"); } } getShoppingCar(){ return this.products; } } const product1: Product = new Product({ id: 1, name: 'laptop', cost: 1000 }) const product2: Product = new Product({ id: 2, name: 'ps5', cost: 700 }) const product3: Product = new Product({ id: 3, name: 'keyboard', cost: 50 }) const shoppingCar = ShoppingCar.getInstance(); shoppingCar.addProduct(product1); shoppingCar.addProduct(product2); shoppingCar.addProduct(product3); shoppingCar.addProduct(product2); shoppingCar.addProduct(product2); shoppingCar.addProduct(product1); shoppingCar.deleteById(2); console.log(shoppingCar.getShoppingCar()); const shoppingCar2 = ShoppingCar.getInstance(); console.log(shoppingCar2.getShoppingCar()); console.log('Shopping Car 1 y Shopping Car 2 son iguales? ', shoppingCar2 === shoppingCar);
Les dejo mi ejercicio en typeScript interface IProduct { id: number; name: string; cost: number;} class Product { private product: IProduct = { id: 0, name: '', cost: 0 } constructor( product: IProduct){ this.product = product } getName(): string { return this.product.name; } getCost(): number { return this.product.cost; } getId(): number { return this.product.id; }} class ShoppingCar { private static instance: ShoppingCar; private products: Product\[] = \[]; private constructor(){ } static getInstance(): ShoppingCar { if(!ShoppingCar.instance){ ShoppingCar.instance = new ShoppingCar(); } return ShoppingCar.instance } addProduct( product: Product) { this.products.push(product); } deleteById( id: number) { const productExist = !!this.products.find((product) => product.getId() === id); if (productExist) { this.products = this.products.filter((prod) => prod.getId() !== id);; } else { console.log(id," doesnt exist"); } } getShoppingCar(){ return this.products; } } const product1: Product = new Product({ id: 1, name: 'laptop', cost: 1000 }) const product2: Product = new Product({ id: 2, name: 'ps5', cost: 700 }) const product3: Product = new Product({ id: 3, name: 'keyboard', cost: 50 }) const shoppingCar = ShoppingCar.getInstance(); shoppingCar.addProduct(product1); shoppingCar.addProduct(product2); shoppingCar.addProduct(product3); shoppingCar.addProduct(product2); shoppingCar.addProduct(product2); shoppingCar.addProduct(product1); shoppingCar.deleteById(2); console.log(shoppingCar.getShoppingCar()); const shoppingCar2 = ShoppingCar.getInstance(); console.log(shoppingCar2.getShoppingCar()); console.log('Shopping Car 1 y Shopping Car 2 son iguales? ', shoppingCar2 === shoppingCar);
Les dejo mi implementación con TS. **product.ts** ```ts export interface ProductType { id: number; name: string; cost: number; } class Product implements ProductType { id: number; name: string; cost: number; constructor ({ id, name, cost }: ProductType) { this.id = id; this.name = name; this.cost = cost; } static getName(product: ProductType) { return product.name; } static getCost(product: ProductType) { return product.cost; } static getId(product: ProductType) { return product.id; } } export default Product; ```**shopingCart.ts**```ts import Product, { ProductType } from "./product"; export interface ShoppingCartInstance { add(product: ProductType): void; deleteById(product: ProductType): void; showProducts(): void; } const searchElementById = findFn => products => products.find(findFn); class ShoppingCart { private static instance: ShoppingCart; private static products: Product[] = []; constructor() {} static getInstance() { if (!ShoppingCart.instance) { ShoppingCart.instance = new ShoppingCart(); } return ShoppingCart.instance; } public add(product: ProductType) { const newProduct = new Product(product); ShoppingCart.products.push(newProduct); } public deleteById(id: ProductType['id']) { const element = searchElementById((value) => (value.id === id))(ShoppingCart.products); const index = ShoppingCart.products.indexOf(element); if (index !== -1) { ShoppingCart.products.splice(index, 1); } else { console.log('El producto con el ID especificado no se encontró en el carrito.'); } } public showProducts() { ShoppingCart.products.forEach((product) => { console.log(product); }); } } export default ShoppingCart; ``` **clientApp.ts**```ts import { ProductType } from "./product"; import ShoppingCart, { ShoppingCartInstance } from "./shopingCart"; const clientApp = () => { const milk: ProductType = { name: 'Milk', cost: 12, id: 1 }; const eggs: ProductType = { name: 'Eggs', cost: 3, id: 2 }; const ham: ProductType = { name: 'Ham', cost: 20, id: 3 }; const shopingInstance = ShoppingCart.getInstance(); shopingInstance.add(milk); shopingInstance.add(eggs); shopingInstance.add(ham); shopingInstance.showProducts(); console.log('--------------'); shopingInstance.deleteById(2); shopingInstance.showProducts(); console.log('--------------'); }; clientApp(); ```
![](https://static.platzi.com/media/user_upload/2-50581a75-eb5e-410f-b1fe-d1464949dfe7.jpg) ![](https://static.platzi.com/media/user_upload/1-5886255b-2123-4ee1-bae5-0003ce98bfea.jpg)
Les comparto mi solución. 😁 Product.ts ![](https://static.platzi.com/media/user_upload/2-9d34684a-68b7-4069-8a16-64398bb49c18.jpg) ![](https://platzi.com/new-home/clases/6933-patrones-diseno-creacionales/60865-singleton-pros-y-contras/)```ts interface ProductAtributes { id: number; name: string; cost: number; } export class Product { #id: number; #name: string; #cost: number; public constructor({ id, name, cost }: ProductAtributes) { this.#id = id; this.#name = name; this.#cost = cost; } public get name(): string { return this.#name; } public get cost(): number { return this.#cost; } public get id(): number { return this.#id; } } ```ShoppingCart.ts ![](https://static.platzi.com/media/user_upload/1-011030a4-94b8-40a2-8bdc-f9b30b616bfc.jpg) ```ts import { Product } from './Product.ts'; export class ShoppingCart { #products: Product[] = []; static #instance: ShoppingCart; private constructor() {} public getProducts(): Product[] { return this.#products; } public add(product: Product): void { this.#products.push(product); } public deleteById(id: number): void { const INDEX_DELETED = this.#products.findIndex( (product) => product.id === id, ); if (~INDEX_DELETED /* INDEX_DELETED !== -1 */) { this.#products.splice(INDEX_DELETED, 1); } } public static getInstance(): ShoppingCart { if (!this.#instance) { this.#instance = new ShoppingCart(); } return this.#instance; } } ```
Este es mi reto ```js class Product { private id: number; private name: string; private cost: number; constructor(id: number, name: string, cost: number) { this.id = id; this.name = name; this.cost = cost; } getId() { return this.id; } getName() { return this.name; } getCost() { return this.cost; } } class ShoppingCar { private static instance: ShoppingCar; private products: { product: Product; quantity: number; }[] = []; private constructor() {} static getInstance() { if (!ShoppingCar.instance) { ShoppingCar.instance = new ShoppingCar(); } return ShoppingCar.instance; } add(product: Product) { let productIndex = this.products.findIndex( (item) => item.product.getId() === product.getId() ); if (productIndex !== -1) { this.products[productIndex] = { ...this.products[productIndex], quantity: this.products[productIndex].quantity + 1, }; } else { this.products.push({ product, quantity: 1 }); } } deleteById(id: number) { let productIndex = this.products.findIndex( (item) => item.product.getId() === id ); if (productIndex !== -1) { this.products = this.products.filter(({ product }) => product.getId() !== id); } } } function appShoppingCar() { const shoppingCar = ShoppingCar.getInstance(); const product1 = new Product(1, "Product 1", 100); const product2 = new Product(2, "Product 2", 200); shoppingCar.add(product1); shoppingCar.add(product1); shoppingCar.add(product2); shoppingCar.deleteById(product1.getId()); } appShoppingCar(); ```

¡Hola!

Dejé mi solución al reto en TypeScript y en Java en mi repositorio en GitHub, también dejé un tutorial con el link al repositorio, pero para este reto en Java, se encuentra aquí.

El concepto de “un solo punto de acceso global” también es conocido como Single Source of Truth (única fuente de verdad).

Solución 😄…

.
.
.
.

class Product {
  private id: number;
  private name: string;
  private cost: number;

  constructor(id: number, name: string, cost: number) {
    this.id = id;
    this.name = name;
    this.cost = cost;
  }

  public getId(): number {
    return this.id;
  }

  public getName(): string {
    return this.name;
  }

  public getCost(): number {
    return this.cost;
  }
}

class ShoppingCart {
  private static instance: ShoppingCart;
  private products: Product[] = [];

  private constructor() {}

  public addProduct(product: Product) {
    this.products.push(product);
  }

  public deleteById(id: number) {
    const index = this.products.findIndex((item) => item.getId() === id);
    if (index !== -1) {
      this.products.splice(index, 1);
    }
  }

  public static getInstance(): ShoppingCart {
    if (!ShoppingCart.instance) {
      ShoppingCart.instance = new ShoppingCart();
    }
    return ShoppingCart.instance;
  }

  public getProducts(): Product[] {
    return this.products;
  }
}

function shoppingApp() {
  const cart1 = ShoppingCart.getInstance();
  const cart2 = ShoppingCart.getInstance();
  const prod1 = new Product(1, "Apple", 21);
  const prod2 = new Product(2, "Orange", 29);
  const prod3 = new Product(3, "Strawberry", 94);

  cart1.addProduct(prod1);
  cart1.addProduct(prod2);
  cart2.addProduct(prod3);

  console.log(cart1 === cart2);
  console.log(cart1.getProducts());
  console.log(cart2.getProducts());

  cart1.deleteById(3);
  console.log(cart1.getProducts());
  console.log(cart2.getProducts());
}

shoppingApp();

Mi solución. Solo permite crear una instancia del carrito, por usuario

export class Product {
  constructor(
    private _id: number,
    private _name: string,
    private _cost: number
  ) {}

  get id() {
    return this._id;
  }

  get name() {
    return this._name;
  }

  get cost() {
    return this._cost;
  }
}

export class ShoppingCar {
  private static instances: { [client: string]: ShoppingCar } = {};
  private products: Product[];

  private constructor() {
    this.products = [];
  }

  static getIntance(client: string): ShoppingCar {
    if (!ShoppingCar.instances[client]) {
      ShoppingCar.instances[client] = new ShoppingCar();
    }
    return ShoppingCar.instances[client];
  }

  add(product: Product) {
    this.products.push(product);
  }

  deleteById() {}

  getProducts() {
    return this.products;
  }
}

const ClientApp = () => {
  console.info('🚀ClientApp:\n');

  /**
   * A pesar de que se intentan crear 4 carror, el sistema solo permite
   * crear un carro por cliente, lo que quiere decir que los 2 carros de
   * Pedro, son el mismo
   */
  const pedroCar = ShoppingCar.getIntance('Pedro');

  const mariaCar = ShoppingCar.getIntance('Maria');

  const pedroCar2 = ShoppingCar.getIntance('Pedro');

  const mariaCar2 = ShoppingCar.getIntance('Maria');

  // Se comparan los carros para validar que solo hay 2
  console.info('pedroCar === pedroCar2:', pedroCar === pedroCar2);
  console.info('mariaCar === mariaCar2:', mariaCar === mariaCar2);

  console.info('pedroCar === mariaCar:', pedroCar === mariaCar);

  // Se crean los productos a agregar
  const camisa = new Product(1, 'Camisa', 1500);
  const pantalon = new Product(2, 'Pantalon', 2000);
  const medias = new Product(3, 'Medias', 300);

  // Agrega productos al carro de Pedro
  pedroCar.add(camisa);
  pedroCar.add(pantalon);
  pedroCar.add(medias);

  // Agrega productos al carro de María
  mariaCar.add(medias);

  // Ambos carros son el mismo
  console.info('pedroCar:', pedroCar.getProducts());
  console.info('pedroCar2:', pedroCar2.getProducts());

  // Ambos carros son el mismo
  console.info('mariaCar:', mariaCar.getProducts());
  console.info('mariaCar2:', mariaCar2.getProducts());
};

ClientApp();