The picture was taken from boredpanda.
Hello everyone!
Starting my first post with one of the most basic but never unnecessary topics; Design patterns.
Let's start listing them:
.
├── Creational Patterns
│ ├── Singleton
│ ├── Factory Method
│ ├── Builder
│ ├── Abstract Factory
│ ├── Prototype
├── Structural Patterns
│ ├── Adapter
│ ├── Decorator
│ ├── Facade
│ ├── Composite
│ ├── Proxy
├── Behavioral Patterns
│ ├── Observer
│ ├── Strategy
│ ├── Command
│ ├── Chain of Responsibility
│ ├── Mediator
│ ├── State
│ ├── Template Method
.
Creational Patterns
This post will focus on Creational Patterns
and how to construct them with swift and javascript. So, Let's start!
Singleton
Ensures a class has only one instance and provides a global point of access to it.
Use case: A central configuration manager for app settings.
Swift:
class ConfigurationManager {
static let shared = ConfigurationManager()
private init() { }
var settings: [String: Any] = [:]
func updateSetting(key: String, value: Any) {
settings[key] = value
}
func getSetting(key: String) -> Any? {
return settings[key]
}
}
// Usage
ConfigurationManager.shared.updateSetting(key: "theme", value: "dark")
let theme = ConfigurationManager.shared.getSetting(key: "theme")
JavaScript:
class ConfigurationManager {
constructor() {
if (ConfigurationManager.instance == null) {
this.settings = {};
ConfigurationManager.instance = this;
}
return ConfigurationManager.instance;
}
updateSetting(key, value) {
this.settings[key] = value;
}
getSetting(key) {
return this.settings[key];
}
}
const instance = new ConfigurationManager();
Object.freeze(instance);
// Usage
instance.updateSetting("theme", "dark");
const theme = instance.getSetting("theme");
Factory Method
Defines an interface for creating different objects from a superclass or protocol from another object.
Use Case: Handling different types of payment gateways (e.g., PayPal, Stripe, Apple Pay).
Swift:
enum PaymentProvider {
case paypal
case stripe
}
protocol PaymentGateway {
func processPayment(amount: Double)
}
class PayPal: PaymentGateway {
func processPayment(amount: Double) {
print("Processing payment through PayPal: \(amount)")
}
}
class Stripe: PaymentGateway {
func processPayment(amount: Double) {
print("Processing payment through Stripe: \(amount)")
}
}
class PaymentGatewayFactory {
static func createPaymentGateway(type: PaymentProvider) -> PaymentGateway? {
switch type {
case .paypal:
return PayPal()
case .stripe:
return Stripe()
default:
return nil
}
}
}
// Usage
let gateway = PaymentGatewayFactory.createPaymentGateway(type: "PayPal")
gateway?.processPayment(amount: 100.0)
JavaScript:
class PayPal {
processPayment(amount) {
console.log(`Processing payment through PayPal: ${amount}`);
}
}
class Stripe {
processPayment(amount) {
console.log(`Processing payment through Stripe: ${amount}`);
}
}
class PaymentGatewayFactory {
static createPaymentGateway(type) {
switch (type) {
case "PayPal":
return new PayPal();
case "Stripe":
return new Stripe();
default:
return null;
}
}
}
// Usage
const gateway = PaymentGatewayFactory.createPaymentGateway("PayPal");
gateway.processPayment(100.0);
Builder
Separates the whole construction process of a complex object, allowing to create different representations of it.
Use Case: Creating complex UI components such as custom dialog boxes.
Swift
class Dialog {
var title: String = ""
var message: String = ""
var buttons: [String] = []
func show() {
print("Title: \(title)")
print("Message: \(message)")
print("Buttons: \(buttons.joined(separator: ", "))")
}
}
class DialogBuilder {
private var dialog = Dialog()
func setTitle(_ title: String) -> DialogBuilder {
dialog.title = title
return self
}
func setMessage(_ message: String) -> DialogBuilder {
dialog.message = message
return self
}
func addButton(_ button: String) -> DialogBuilder {
dialog.buttons.append(button)
return self
}
func build() -> Dialog {
return dialog
}
}
// Usage
let dialog = DialogBuilder()
.setTitle("Warning")
.setMessage("Are you sure you want to delete this file?")
.addButton("Cancel")
.addButton("Delete")
.build()
dialog.show()
JavaScript:
class Dialog {
constructor() {
this.title = "";
this.message = "";
this.buttons = [];
}
show() {
console.log(`Title: ${this.title}`);
console.log(`Message: ${this.message}`);
console.log(`Buttons: ${this.buttons.join(", ")}`);
}
}
class DialogBuilder {
constructor() {
this.dialog = new Dialog();
}
setTitle(title) {
this.dialog.title = title;
return this;
}
setMessage(message) {
this.dialog.message = message;
return this;
}
addButton(button) {
this.dialog.buttons.push(button);
return this;
}
build() {
return this.dialog;
}
}
// Usage
const dialog = new DialogBuilder()
.setTitle("Warning")
.setMessage("Are you sure you want to delete this file?")
.addButton("Cancel")
.addButton("Delete")
.build();
dialog.show();
Abstract Factory
Provides an interface for creating families of related or dependent objects without specifying their concrete classes.
Use Case: Creating families of related or dependent objects without specifying their concrete classes.
Swift
protocol Button {
func render()
}
class WindowsButton: Button {
func render() {
print("Render a button in Windows style")
}
}
class MacOSButton: Button {
func render() {
print("Render a button in MacOS style")
}
}
protocol GUIFactory {
func createButton() -> Button
}
class WindowsFactory: GUIFactory {
func createButton() -> Button {
return WindowsButton()
}
}
class MacOSFactory: GUIFactory {
func createButton() -> Button {
return MacOSButton()
}
}
// Usage
func createUI(factory: GUIFactory) {
let button = factory.createButton()
button.render()
}
let windowsFactory = WindowsFactory()
createUI(factory: windowsFactory)
let macFactory = MacOSFactory()
createUI(factory: macFactory)
JavaScript:
class WindowsButton {
render() {
console.log("Render a button in Windows style");
}
}
class MacOSButton {
render() {
console.log("Render a button in MacOS style");
}
}
class WindowsFactory {
createButton() {
return new WindowsButton();
}
}
class MacOSFactory {
createButton() {
return new MacOSButton();
}
}
// Usage
function createUI(factory) {
const button = factory.createButton();
button.render();
}
const windowsFactory = new WindowsFactory();
createUI(windowsFactory);
const macFactory = new MacOSFactory();
createUI(macFactory);
Prototype
Creates new objects by copying an existing object, known as the prototype.
Use Case: Cloning objects to avoid the cost of creating new instances from scratch.
Swift
protocol Clonable {
func clone() -> Self
}
class Prototype: Clonable {
var name: String
required init(name: String) {
self.name = name
}
func clone() -> Self {
return type(of: self).init(name: self.name)
}
}
// Usage
let original = Prototype(name: "Original")
let copy = original.clone()
copy.name = "Changed"
print(original.name) // Output: Original
print(copy.name) // Output: Changed
JavaScript:
class Prototype {
constructor(name) {
this.name = name;
}
clone() {
return new Prototype(this.name);
}
}
// Usage
const original = new Prototype("Original");
const copy = original.clone();
copy.name = "Changed";
console.log(original.name); // Output: Original
console.log(copy.name); // Output: Changed
Top comments (3)
There is a typo in your last code comment
console.log(copy.name); // Output: Original
the output here is "Changed".Thanks for reading it till the last line <3
Thanks Nick!
Changed! xD