From 2e5e750f795048467800a65ec696b526e86befbe Mon Sep 17 00:00:00 2001 From: mahamd mesalm Date: Fri, 25 Oct 2024 17:28:42 +0300 Subject: [PATCH] Add JavaScript implementations for missing design patterns --- Creational/abstractFactory.js | 228 ++++++++++++++++++++++++++++++++++ Creational/singleton.js | 70 +++++++++++ 2 files changed, 298 insertions(+) create mode 100644 Creational/abstractFactory.js create mode 100644 Creational/singleton.js diff --git a/Creational/abstractFactory.js b/Creational/abstractFactory.js new file mode 100644 index 0000000..47b85b5 --- /dev/null +++ b/Creational/abstractFactory.js @@ -0,0 +1,228 @@ +// AbstractFactory interface +class AbstractFactory { + createProductA() { + throw new Error("This method should be overridden!"); + } + + createProductB() { + throw new Error("This method should be overridden!"); + } +} + +// Concrete Factories produce a family of products that belong to a single variant +class ConcreteFactory1 extends AbstractFactory { + createProductA() { + return new ConcreteProductA1(); + } + + createProductB() { + return new ConcreteProductB1(); + } +} + +class ConcreteFactory2 extends AbstractFactory { + createProductA() { + return new ConcreteProductA2(); + } + + createProductB() { + return new ConcreteProductB2(); + } +} + +// AbstractProductA interface +class AbstractProductA { + usefulFunctionA() { + throw new Error("This method should be overridden!"); + } +} + +// Concrete Products created by corresponding Concrete Factories +class ConcreteProductA1 extends AbstractProductA { + usefulFunctionA() { + return "The result of the product A1."; + } +} + +class ConcreteProductA2 extends AbstractProductA { + usefulFunctionA() { + return "The result of the product A2."; + } +} + +// AbstractProductB interface +class AbstractProductB { + usefulFunctionB() { + throw new Error("This method should be overridden!"); + } + + anotherUsefulFunctionB(collaborator) { + throw new Error("This method should be overridden!"); + } +} + +// Concrete Products created by corresponding Concrete Factories +class ConcreteProductB1 extends AbstractProductB { + usefulFunctionB() { + return "The result of the product B1."; + } + + anotherUsefulFunctionB(collaborator) { + const result = collaborator.usefulFunctionA(); + return `The result of the B1 collaborating with the (${result})`; + } +} + +class ConcreteProductB2 extends AbstractProductB { + usefulFunctionB() { + return "The result of the product B2."; + } + + anotherUsefulFunctionB(collaborator) { + const result = collaborator.usefulFunctionA(); + return `The result of the B2 collaborating with the (${result})`; + } +} + +// Client code works with factories and products through abstract types +function testFactory(factory) { + const productA = factory.createProductA(); + const productB = factory.createProductB(); + + console.log(productB.usefulFunctionB()); + console.log(productB.anotherUsefulFunctionB(productA)); +} + +// Testing the client code with the first factory type +console.log("Client: Testing client code with the first factory type..."); +testFactory(new ConcreteFactory1()); + +// Testing the same client code with the second factory type +console.log( + "Client: Testing the same client code with the second factory type..." +); +testFactory(new ConcreteFactory2()); + +// Layout interface +class Layout { + getSize() { + throw new Error("This method should be overridden!"); + } + + getNavBar() { + throw new Error("This method should be overridden!"); + } +} + +// Concrete Layout classes +class WinLayout extends Layout { + getSize() { + return 8; + } + + getNavBar() { + return "right"; + } +} + +class MacLayout extends Layout { + getSize() { + return 5; + } + + getNavBar() { + return "left"; + } +} + +// Buttons interface +class Buttons { + getMinimizeLocation() { + throw new Error("This method should be overridden!"); + } + + getCloseLocation() { + throw new Error("This method should be overridden!"); + } +} + +// Concrete Button classes +class MacButtons extends Buttons { + getMinimizeLocation() { + return "leftTop"; + } + + getCloseLocation() { + return "leftTop"; + } +} + +class WinButtons extends Buttons { + getMinimizeLocation() { + return "rightTop"; + } + + getCloseLocation() { + return "rightTop"; + } +} + +// AbstractApp interface +class AbstractApp { + createLayout() { + throw new Error("This method should be overridden!"); + } + + createButtons() { + throw new Error("This method should be overridden!"); + } +} + +// Concrete App classes +class WindowsApp extends AbstractApp { + createLayout() { + return new WinLayout(); + } + + createButtons() { + return new WinButtons(); + } +} + +class MacApp extends AbstractApp { + createLayout() { + return new MacLayout(); + } + + createButtons() { + return new MacButtons(); + } +} + +// Client class using the abstract factory +class Client { + constructor(app) { + this.layout = app.createLayout(); + this.buttons = app.createButtons(); + } + + openApp() { + console.log("I am able to open my app"); + console.log( + "layout of my App \n Screen size : " + + this.layout.getSize() + + " , NavBar : " + + this.layout.getNavBar() + ); + console.log( + "Buttons of my App \n minimize : " + + this.buttons.getMinimizeLocation() + + " , close : " + + this.buttons.getCloseLocation() + ); + } +} + +// Example usage +const client1 = new Client(new WindowsApp()); +client1.openApp(); diff --git a/Creational/singleton.js b/Creational/singleton.js new file mode 100644 index 0000000..e1a464c --- /dev/null +++ b/Creational/singleton.js @@ -0,0 +1,70 @@ +// Define the main Singleton class +class Singleton { + static instance; + + // Constructor should be private to prevent creating new instances with 'new' + constructor() { + if (Singleton.instance) { + // If an instance already exists, return it + return Singleton.instance; + } + + // If no instance exists, set this as the new instance + Singleton.instance = this; + + // Any custom properties or methods can be added here + this.foodLog = []; // Example property for logging information + } + + // Public method to access the single instance of the class + static getInstance() { + if (!Singleton.instance) { + Singleton.instance = new Singleton(); + } + return Singleton.instance; + } + + // Business logic for logging, here we add an item to the food log + log(order) { + this.foodLog.push(order.foodItem); + console.log(`Logging order: ${order.foodItem}`); + } + } + + // Test function to verify Singleton behavior + function clientCode() { + const logger1 = Singleton.getInstance(); + const logger2 = Singleton.getInstance(); + + if (logger1 === logger2) { + console.log("Singleton works, both variables contain the same instance."); + } else { + console.log("Singleton failed, variables contain different instances."); + } + } + + // Call the test function to verify + clientCode(); + + // Using the Singleton class within another class like Customer + class Customer { + constructor(order) { + this.price = order.price; + this.food = order.foodItem; + Singleton.getInstance().log(order); // Use the same Singleton instance to log + } + } + + // Restaurant class using the same Singleton + class Restaurant { + constructor(inventory) { + this.quantity = inventory.count; + this.food = inventory.foodItem; + Singleton.getInstance().log(inventory); // Use the same Singleton instance to log + } + } + + // Example usage of the classes + const customer1 = new Customer({ price: 20, foodItem: "Pizza" }); + const restaurant1 = new Restaurant({ count: 5, foodItem: "Burger" }); + \ No newline at end of file