beginner

Improving our example (2)


In our previous post we have created an example with everything we learned so far. But our code has many things that we can improve, both logically and performance wise. So lets start.

class Shop {
  #products;
  constructor() {
    this.#products = {}; // Moving products from array to object
  }

  add(product) {
    this.#products[product.id] = product;
  }

  get products() {
    return this.#products;
  }

  sell(productId) {
    const product = this.#products[productId];
    if (!product) {
      throw new Error(`Product with id [${productId}] not found.`);
    }

    delete this.#products[productId];

    return product;
  }
}

class Product {
  constructor(data) {
    this.id = data.id;
    this.name = data.name;
    this.price = data.price;
    this.currency = data.currency;
  }
}

// Introducing Wallet class to store all money related info
class Wallet {
  #balance;
  #currency;
  constructor(data) {
    this.balance = data.balance;
    this.currency = data.currency;
  }

  get balance() {
    return this.#balance;
  }

  set balance(value) {
    if (value < 0) {
      throw new Error("Value is below 0.");
    }
    if (this.#balance - value < 0) {
      throw new Error("New balance is below 0.");
    }
    this.#balance = value;
  }
}

class Customer {
  #wallet;
  constructor({ id, wallet }) {
    this.id = id;
    this.#wallet = wallet;
  }

  get balance() {
    return this.#wallet.balance;
  }

  buy(data) {
    this.#wallet.balance = this.#wallet.balance - data.product.price;
  }
}

const wallet = new Wallet({
  balance: 1000,
  currency: "EUR",
});

const customerOne = new Customer({
  id: 1,
  wallet: wallet,
});

const shop = new Shop();
const productOne = new Product({
  id: 1,
  name: "Product 1",
  price: 10,
  currency: "EUR",
});
const productTwo = new Product({
  id: 2,
  name: "Product 2",
  price: 20,
  currency: "EUR",
});
shop.add(productOne);
shop.add(productTwo);

shop.sell(productOne.id);
customerOne.buy({ product: productOne });

console.log(customerOne.balance); // 990
console.log(shop.products); // [ `2`: Product]

At first glance, above code seems the same as previous post example but if you look closer you’ll notice some very important differences.

Shop

We have changed our products variable from array to object

//Before
this.products = [];

// Now
this.#products = {};

This has to do with time complexity (known as Big O) and it shows how much time it takes for worst case scenario(⏭️). For our case, if we have n amount of products in our array, what happens if we want to delete one specific product? We need to go through for loop until we find that specific product and then remove it from array. So if that product is last in array we would have to go through for loop n times. But if we use object instead then set our key to be id of product and value to be Product object we can immediately find that product and remove it. That is exactly what we do in add and sell functions.

Product stays the same

Wallet

Newly introduced class that hold balance and currency values. The reason we have introduced this class is because Customer should not know anything about the implementation of a wallet, it should only know that it has access to a wallet of sorts but it should not worry/know anything about how that wallet makes changes to balance. This is why we have moved our set balance from Customer to Wallet.

Customer

Almost the same as before but now we instantiate wallet and pass it in as a parameter for customer. We have also made slight change to buy(data) function.

What Now?

Now that we have somewhat improved our code try to find even more ways to improve it. For example, what happens if wallet currency and product currency are not the same? If you want easier solution then just make it possible to buy when the currency is the same and if you want harder and better solution then try to make your own conversion function that has few most popular currencies and conversion between them.

Previous Example for everything so far (1)
Next Handling errors