Created
July 11, 2024 03:11
-
-
Save ThatXliner/c114dab9499785632f195b93140bb580 to your computer and use it in GitHub Desktop.
OOP Design Patterns
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Adapter pattern example for integrating different payment gateways | |
class PayPal { | |
makePayment(amount) { | |
console.log(`Paying ${amount} via PayPal`); | |
} | |
} | |
class Stripe { | |
pay(amount) { | |
console.log(`Paying ${amount} via Stripe`); | |
} | |
} | |
// Adapter for Stripe to conform to PayPal interface | |
class StripeAdapter { | |
constructor(stripe) { | |
this.stripe = stripe; | |
} | |
makePayment(amount) { | |
this.stripe.pay(amount); | |
} | |
} | |
// Usage | |
const paypal = new PayPal(); | |
const stripe = new Stripe(); | |
const stripeAdapter = new StripeAdapter(stripe); | |
paypal.makePayment(100); // Paying 100 via PayPal | |
stripeAdapter.makePayment(200); // Paying 200 via Stripe |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Builder pattern example for creating a complex object step by step | |
// This example may seem like a toy (it is) | |
// but a real-life example (which I use in FRC) of a Builder pattern API | |
// can be found here (note that it's in Java): | |
// https://api.ctr-electronics.com/phoenix6/release/java/com/ctre/phoenix6/configs/Slot0Configs.html | |
// (for the above example, take note of the `with*` methods such as `.withKV`) | |
class Product { | |
constructor() { | |
this.parts = []; | |
} | |
addPart(part) { | |
this.parts.push(part); | |
} | |
showParts() { | |
console.log('Product parts:', this.parts.join(', ')); | |
} | |
} | |
class ProductBuilder { | |
constructor() { | |
this.product = new Product(); | |
} | |
buildPartA() { | |
this.product.addPart('Part A'); | |
return this; | |
} | |
buildPartB() { | |
this.product.addPart('Part B'); | |
return this; | |
} | |
getProduct() { | |
return this.product; | |
} | |
} | |
// Usage | |
const builder = new ProductBuilder(); | |
const product = builder.buildPartA().buildPartB().getProduct(); | |
product.showParts(); // Product parts: Part A, Part B |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Decorator pattern example for adding toppings to a pizza | |
class Pizza { | |
getDescription() { | |
return 'Plain pizza'; | |
} | |
cost() { | |
return 10; | |
} | |
} | |
class TomatoSauceDecorator { | |
constructor(pizza) { | |
this.pizza = pizza; | |
} | |
getDescription() { | |
return this.pizza.getDescription() + ' with tomato sauce'; | |
} | |
cost() { | |
return this.pizza.cost() + 2; | |
} | |
} | |
class CheeseDecorator { | |
constructor(pizza) { | |
this.pizza = pizza; | |
} | |
getDescription() { | |
return this.pizza.getDescription() + ' with cheese'; | |
} | |
cost() { | |
return this.pizza.cost() + 3; | |
} | |
} | |
// Usage | |
let pizza = new Pizza(); | |
console.log(pizza.getDescription(), 'Cost:', pizza.cost()); | |
pizza = new TomatoSauceDecorator(pizza); | |
console.log(pizza.getDescription(), 'Cost:', pizza.cost()); | |
pizza = new CheeseDecorator(pizza); | |
console.log(pizza.getDescription(), 'Cost:', pizza.cost()); | |
// Output: | |
// Plain pizza Cost: 10 | |
// Plain pizza with tomato sauce Cost: 12 | |
// Plain pizza with tomato sauce with cheese Cost: 15 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Factory pattern example for creating different shapes | |
class ShapeFactory { | |
createShape(type) { | |
switch (type) { | |
case 'circle': | |
return new Circle(); | |
case 'rectangle': | |
return new Rectangle(); | |
default: | |
throw new Error('Invalid shape type'); | |
} | |
} | |
} | |
class Circle { | |
draw() { | |
console.log('Drawing a circle'); | |
} | |
} | |
class Rectangle { | |
draw() { | |
console.log('Drawing a rectangle'); | |
} | |
} | |
// Usage | |
const factory = new ShapeFactory(); | |
const circle = factory.createShape('circle'); | |
const rectangle = factory.createShape('rectangle'); | |
circle.draw(); // Drawing a circle | |
rectangle.draw(); // Drawing a rectangle |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Proxy pattern example for controlling access to a sensitive object | |
class SensitiveObject { | |
constructor(data) { | |
this.data = data | |
} | |
access() { | |
console.log('Accessing sensitive object'); | |
return this.data; | |
} | |
} | |
class ProxyObject { | |
constructor(sensitiveObject) { | |
this.sensitiveObject = sensitiveObject; | |
} | |
access() { | |
if (this.checkAccess()) { | |
return this.sensitiveObject.access(); | |
} else { | |
console.log('Access denied'); | |
} | |
} | |
checkAccess() { | |
// Perform validation or checks here | |
return false; // Simulating access denial for demonstration | |
} | |
} | |
// Usage | |
const sensitiveObject = new SensitiveObject('sensitive data'); | |
const proxy = new ProxyObject(sensitiveObject); | |
proxy.access(); // Access denied |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Proxy pattern example for controlling access to a sensitive object | |
// but taking advantage of JavaScript's Proxy class | |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy | |
// Exact same class as before | |
class SensitiveObject { | |
constructor(data) { | |
this.data = data; | |
} | |
access() { | |
console.log('Accessing sensitive object'); | |
return this.data; | |
} | |
} | |
// Proxy handler for access control | |
const handler = { | |
get(target, property) { | |
if (property === 'data' && !this.checkAccess()) { | |
console.log('Access denied'); | |
return undefined; | |
} | |
if (property === 'access') { | |
if (this.checkAccess()) { | |
return target[property].bind(target); | |
} else { | |
return () => console.log('Access denied'); | |
} | |
} | |
console.log(`Accessing property '${property}'`); | |
return target[property]; | |
}, | |
checkAccess() { | |
// Perform validation or checks here | |
return false; // Simulating access denial for demonstration | |
} | |
}; | |
// Creating a proxy object | |
const sensitiveObject = new SensitiveObject('sensitive data'); | |
const proxy = new Proxy(sensitiveObject, handler); | |
// Using the proxy object | |
console.log(proxy.data); // Access denied, undefined | |
proxy.access(); // Access denied | |
// Modifying the checkAccess method to grant access | |
handler.checkAccess = function() { | |
return true; // Granting access for demonstration | |
}; | |
console.log(proxy.data); // Accessing property 'data', Sensitive data | |
proxy.access(); // Accessing sensitive object |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Singleton example for a Configuration Manager | |
class ConfigurationManager { | |
constructor() { | |
if (ConfigurationManager.instance) { | |
return ConfigurationManager.instance; | |
} | |
// Initialize configuration here | |
this.config = { | |
language: 'en', | |
theme: 'light' | |
}; | |
ConfigurationManager.instance = this; | |
return this; | |
} | |
getConfig() { | |
return this.config; | |
} | |
setConfig(config) { | |
this.config = config; | |
} | |
} | |
// Usage | |
const configManager1 = new ConfigurationManager(); | |
const configManager2 = new ConfigurationManager(); | |
console.log(configManager1 === configManager2); // true (same instance) | |
configManager1.setConfig({ language: 'fr', theme: 'dark' }); | |
console.log(configManager2.getConfig()); // { language: 'fr', theme: 'dark' } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment