Design Principle: Composition Over Inheritance(COI)

Summary

Principle NameComposition Over Inheritance
AcronymCOI
Principle Type Core Principle
PurposeBuild complex objects by combining simpler objects.
Implementing
Design Patterns
Adapter Pattern
Composite Pattern
Decorator Pattern
Factory Pattern
Proxy Pattern
Strategy Pattern
Related Principles Dependency Inversion Principle(DIP)
Interface Segregation Principle(ISP)
Open-Closed Principle(OCP)
Liskov Substitution Principle(LSP)
Separation of Concerns(SoC)
Single Responsibility Principle(SRP)

Definition

Inheritance is very useful, but it leads to tight coupling. And tight coupling makes the code, hard to maintain. So we should avoid inheritance whenever we can.

If we use inheritance while creating a complex object, it will result in code that is not maintainable, and very difficult to change later.

The Composition Over Inheritance(COI) principle is-

We should prefer composing objects while creating a complex object, rather than relying on inheritance.

This means, whenever possible we should avoid hierarchies of class inheritance, and compose objects of a class when we need it.

NOTES

Following this principle will also enable us to change the object’s behavior at runtime.

Implementation

NOTES

When classes have relation using inheritance, then it is referred to as an “is-a” relationship.

When classes are composed of other classes, then it is referred as a “has-a” relationship.

Example #1: Camera Operation

We have a camera class, and a class for lenses. We use the lens operations in the camera class. To do that we need an instance of “Lens” class inside our “Camera” class.

Let’s see how can we do this-

Implementation using Inheritance (not recommended)

class Lens {
    private String brand;
    private int focalLength;

    public Lens(String brand, int focalLength) {
        this.brand = brand;
        this.focalLength = focalLength;
    }

    public void zoomIn(int amount) {
        focalLength += amount;
        System.out.println("Zooming in(" + amount + "mm): new focal length " + focalLength + "mm.");
    }

    public void zoomOut(int amount) {
        if (focalLength - amount > 0) {
            focalLength -= amount;
            System.out.println("Zooming out(" + amount + "mm): new focal length " + focalLength + "mm.");
        } else {
            System.out.println("Cannot zoom out further.");
        }
    }

    public String getBrand() {
        return brand;
    }

    public int getFocalLength() {
        return focalLength;
    }
}

class Camera extends Lens {
    private String model;

    public Camera(String model, String brand, int focalLength) {
        super(brand, focalLength);
        this.model = model;
    }

    public void adjust(int amount) {
        if (amount >= 0) {
            zoomIn(amount);
        } else {
            zoomOut(-amount);
        }
    }

    public void capture() {
        System.out.println("Image captured with settings:");
        System.out.println("Camera Model: " + model);
        System.out.println("Lens Model: " + getBrand());
        System.out.println("Lens focal length: " + getFocalLength() + "mm");
    }

    public static void main(String[] args) {
        Camera camera = new Camera("Canon EOS R5", "Canon", 18);
        camera.capture();

        camera.adjust(10);
        camera.capture();

        camera.adjust(-5);
        camera.capture();
    }
}
Java
class Lens:
    def __init__(self, brand: str, focal_length: int) -> None:
        self.brand: str = brand
        self.focal_length: int = focal_length

    def zoom_in(self, amount: int) -> None:
        self.focal_length += amount
        print(f"Zooming in({amount}mm): new focal length {self.focal_length}mm.")

    def zoom_out(self, amount: int) -> None:
        if self.focal_length - amount > 0:
            self.focal_length -= amount
            print(f"Zooming out({amount}mm): new focal length {self.focal_length}mm.")
        else:
            print("Cannot zoom out further.")

class Camera(Lens):  # Camera inherits from Lens
    def __init__(self, model: str, brand: str, focal_length: int) -> None:
        super().__init__(brand, focal_length)
        self.model: str = model

    def adjust(self, amount: int) -> None:
        if amount >= 0:
            self.zoom_in(amount)
        else:
            self.zoom_out(abs(amount))

    def capture(self) -> None:
        print("Image captured with settings:")
        print(f"Camera Model: {self.model}")
        print(f"Lens Model: {self.brand}")
        print(f"Lens focal length: {self.focal_length}mm")


# Demo usage
camera = Camera("Canon EOS R5", "Canon", 18)

camera.capture()

camera.adjust(10)
camera.capture()

camera.adjust(-5)
camera.capture()
Python
package main

import "fmt"

type Lens struct {
    brand       string
    focalLength int
}

func (l *Lens) zoomIn(amount int) {
    l.focalLength += amount
    fmt.Printf("Zooming in(%dmm): new focal length %dmm.\n", amount, l.focalLength)
}

func (l *Lens) zoomOut(amount int) {
    if l.focalLength-amount > 0 {
        l.focalLength -= amount
        fmt.Printf("Zooming out(%dmm): new focal length %dmm.\n", amount, l.focalLength)
    } else {
        fmt.Println("Cannot zoom out further.")
    }
}

type Camera struct {
    Lens
    model string
}

func NewCamera(model, brand string, focalLength int) *Camera {
    return &Camera{
        Lens:  Lens{brand: brand, focalLength: focalLength},
        model: model,
    }
}

func (c *Camera) Adjust(amount int) {
    if amount >= 0 {
        c.zoomIn(amount)
    } else {
        c.zoomOut(-amount)
    }
}

func (c *Camera) Capture() {
    fmt.Println("Image captured with settings:")
    fmt.Printf("Camera Model: %s\n", c.model)
    fmt.Printf("Lens Model: %s\n", c.brand)
    fmt.Printf("Lens focal length: %dmm\n", c.focalLength)
}

func main() {
    camera := NewCamera("Canon EOS R5", "Canon", 18)
    camera.Capture()

    camera.Adjust(10)
    camera.Capture()

    camera.Adjust(-5)
    camera.Capture()
}
Go
<?php

class Lens {
    protected $brand;
    protected $focalLength;

    public function __construct($brand, $focalLength) {
        $this->brand = $brand;
        $this->focalLength = $focalLength;
    }

    public function zoomIn($amount) {
        $this->focalLength += $amount;
        echo "Zooming in($amount mm): new focal length {$this->focalLength}mm.\n";
    }

    public function zoomOut($amount) {
        if ($this->focalLength - $amount > 0) {
            $this->focalLength -= $amount;
            echo "Zooming out($amount mm): new focal length {$this->focalLength}mm.\n";
        } else {
            echo "Cannot zoom out further.\n";
        }
    }

    public function getBrand() {
        return $this->brand;
    }

    public function getFocalLength() {
        return $this->focalLength;
    }
}

class Camera extends Lens {
    private $model;

    public function __construct($model, $brand, $focalLength) {
        parent::__construct($brand, $focalLength);
        $this->model = $model;
    }

    public function adjust($amount) {
        if ($amount >= 0) {
            $this->zoomIn($amount);
        } else {
            $this->zoomOut(-$amount);
        }
    }

    public function capture() {
        echo "Image captured with settings:\n";
        echo "Camera Model: {$this->model}\n";
        echo "Lens Model: {$this->getBrand()}\n";
        echo "Lens focal length: {$this->getFocalLength()}mm\n";
    }
}

// Demo usage
$camera = new Camera("Canon EOS R5", "Canon", 18);
$camera->capture();

$camera->adjust(10);
$camera->capture();

$camera->adjust(-5);
$camera->capture();
PHP
class Lens {
    brand: string;
    focalLength: number;

    constructor(brand: string, focalLength: number) {
        this.brand = brand;
        this.focalLength = focalLength;
    }

    zoomIn(amount: number): void {
        this.focalLength += amount;
        console.log(`Zooming in(${amount}mm): new focal length ${this.focalLength}mm.`);
    }

    zoomOut(amount: number): void {
        if (this.focalLength - amount > 0) {
            this.focalLength -= amount;
            console.log(`Zooming out(${amount}mm): new focal length ${this.focalLength}mm.`);
        } else {
            console.log("Cannot zoom out further.");
        }
    }
}

class Camera extends Lens {
    model: string;

    constructor(model: string, brand: string, focalLength: number) {
        super(brand, focalLength);
        this.model = model;
    }

    adjust(amount: number): void {
        if (amount >= 0) {
            this.zoomIn(amount);
        } else {
            this.zoomOut(-amount);
        }
    }

    capture(): void {
        console.log("Image captured with settings:");
        console.log(`Camera Model: ${this.model}`);
        console.log(`Lens Model: ${this.brand}`);
        console.log(`Lens focal length: ${this.focalLength}mm`);
    }
}

// Demo usage
const camera = new Camera("Canon EOS R5", "Canon", 18);
camera.capture();

camera.adjust(10);
camera.capture();

camera.adjust(-5);
camera.capture();
TypeScript

Implementation using Composition (recommended)

class Lens {
    private String brand;
    private int focalLength;

    public Lens(String brand, int focalLength) {
        this.brand = brand;
        this.focalLength = focalLength;
    }

    public void zoomIn(int amount) {
        focalLength += amount;
        System.out.println("Zooming in(" + amount + "mm): new focal length " + focalLength + "mm.");
    }

    public void zoomOut(int amount) {
        if (focalLength - amount > 0) {
            focalLength -= amount;
            System.out.println("Zooming out(" + amount + "mm): new focal length " + focalLength + "mm.");
        } else {
            System.out.println("Cannot zoom out further.");
        }
    }

    public String getBrand() {
        return brand;
    }

    public int getFocalLength() {
        return focalLength;
    }
}

class Camera {
    private String model;
    private Lens lens;

    public Camera(String model, Lens lens) {
        this.model = model;
        this.lens = lens;
    }

    public void adjust(int amount) {
        if (amount >= 0) {
            lens.zoomIn(amount);
        } else {
            lens.zoomOut(Math.abs(amount));
        }
    }

    public void capture() {
        if (lens != null) {
            System.out.println("Image captured with settings:");
            System.out.println("Camera Model: " + model);
            System.out.println("Lens Model: " + lens.getBrand());
            System.out.println("Lens focal length: " + lens.getFocalLength() + "mm");
        } else {
            System.out.println("Lens not attached.");
        }
    }

    public static void main(String[] args) {
        Lens lens = new Lens("Canon", 18);
        Camera camera = new Camera("Canon EOS R5", lens);

        camera.capture();

        camera.adjust(10);
        camera.capture();

        camera.adjust(-5);
        camera.capture();
    }
}
Java
class Camera:
    def __init__(self, model: str, lens: "Lens") -> None:
        self.model: str = model
        self.lens: Lens = lens  # Or you can create a new object here instead of getting it as param

    def adjust(self, amount: int) -> None:
        if amount >= 0:
            self.lens.zoom_in(amount)
        else:
            self.lens.zoom_out(abs(amount))

    def capture(self) -> None:
        if self.lens:
            print("Image captured with settings:")
            print(f"Camera Model: {self.model}")
            print(f"Lens Model: {self.lens.brand}")
            print(f"Lens focal length: {self.lens.focal_length}mm")
        else:
            print("Lens not attached.")


class Lens:
    def __init__(self, brand: str, focal_length: int) -> None:
        self.brand: str = brand
        self.focal_length: int = focal_length

    def zoom_in(self, amount: int) -> None:
        self.focal_length += amount
        print(f"Zooming in({amount}mm): new focal length {self.focal_length}mm.")

    def zoom_out(self, amount: int) -> None:
        if self.focal_length - amount > 0:
            self.focal_length -= amount
            print(f"Zooming out({amount}mm): new focal length {self.focal_length}mm.")
        else:
            print("Cannot zoom out further.")


# Demo usage
lens = Lens("Canon", 18)
camera = Camera("Canon EOS R5", lens)

camera.capture()

camera.adjust(10)
camera.capture()

camera.adjust(-5)
camera.capture()
Python
package main

import "fmt"

type Lens struct {
    brand       string
    focalLength int
}

func (l *Lens) zoomIn(amount int) {
    l.focalLength += amount
    fmt.Printf("Zooming in(%dmm): new focal length %dmm.\n", amount, l.focalLength)
}

func (l *Lens) zoomOut(amount int) {
    if l.focalLength-amount > 0 {
        l.focalLength -= amount
        fmt.Printf("Zooming out(%dmm): new focal length %dmm.\n", amount, l.focalLength)
    } else {
        fmt.Println("Cannot zoom out further.")
    }
}

type Camera struct {
    model string
    lens  Lens
}

func NewCamera(model string, lens Lens) *Camera {
    return &Camera{model: model, lens: lens}
}

func (c *Camera) Adjust(amount int) {
    if amount >= 0 {
        c.lens.zoomIn(amount)
    } else {
        c.lens.zoomOut(-amount)
    }
}

func (c *Camera) Capture() {
    fmt.Println("Image captured with settings:")
    fmt.Printf("Camera Model: %s\n", c.model)
    fmt.Printf("Lens Model: %s\n", c.lens.brand)
    fmt.Printf("Lens focal length: %dmm\n", c.lens.focalLength)
}

func main() {
    lens := Lens{"Canon", 18}
    camera := NewCamera("Canon EOS R5", lens)

    camera.Capture()

    camera.Adjust(10)
    camera.Capture()

    camera.Adjust(-5)
    camera.Capture()
}
Go
<?php

class Lens {
    private $brand;
    private $focalLength;

    public function __construct($brand, $focalLength) {
        $this->brand = $brand;
        $this->focalLength = $focalLength;
    }

    public function zoomIn($amount) {
        $this->focalLength += $amount;
        echo "Zooming in($amount mm): new focal length {$this->focalLength}mm.\n";
    }

    public function zoomOut($amount) {
        if ($this->focalLength - $amount > 0) {
            $this->focalLength -= $amount;
            echo "Zooming out($amount mm): new focal length {$this->focalLength}mm.\n";
        } else {
            echo "Cannot zoom out further.\n";
        }
    }

    public function getBrand() {
        return $this->brand;
    }

    public function getFocalLength() {
        return $this->focalLength;
    }
}

class Camera {
    private $model;
    private $lens;

    public function __construct($model, $lens) {
        $this->model = $model;
        $this->lens = $lens;
    }

    public function adjust($amount) {
        if ($amount >= 0) {
            $this->lens->zoomIn($amount);
        } else {
            $this->lens->zoomOut(abs($amount));
        }
    }

    public function capture() {
        if ($this->lens) {
            echo "Image captured with settings:\n";
            echo "Camera Model: {$this->model}\n";
            echo "Lens Model: {$this->lens->getBrand()}\n";
            echo "Lens focal length: {$this->lens->getFocalLength()}mm\n";
        } else {
            echo "Lens not attached.\n";
        }
    }
}

// Demo usage
$lens = new Lens("Canon", 18);
$camera = new Camera("Canon EOS R5", $lens);

$camera->capture();

$camera->adjust(10);
$camera->capture();

$camera->adjust(-5);
$camera->capture();
PHP
class Lens {
    brand: string;
    focalLength: number;

    constructor(brand: string, focalLength: number) {
        this.brand = brand;
        this.focalLength = focalLength;
    }

    zoomIn(amount: number): void {
        this.focalLength += amount;
        console.log(`Zooming in(${amount}mm): new focal length ${this.focalLength}mm.`);
    }

    zoomOut(amount: number): void {
        if (this.focalLength - amount > 0) {
            this.focalLength -= amount;
            console.log(`Zooming out(${amount}mm): new focal length ${this.focalLength}mm.`);
        } else {
            console.log("Cannot zoom out further.");
        }
    }
}

class Camera {
    model: string;
    lens: Lens;

    constructor(model: string, lens: Lens) {
        this.model = model;
        this.lens = lens;
    }

    adjust(amount: number): void {
        if (amount >= 0) {
            this.lens.zoomIn(amount);
        } else {
            this.lens.zoomOut(Math.abs(amount));
        }
    }

    capture(): void {
        if (this.lens) {
            console.log("Image captured with settings:");
            console.log(`Camera Model: ${this.model}`);
            console.log(`Lens Model: ${this.lens.brand}`);
            console.log(`Lens focal length: ${this.lens.focalLength}mm`);
        } else {
            console.log("Lens not attached.");
        }
    }
}

// Demo usage
const lens = new Lens("Canon", 18);
const camera = new Camera("Canon EOS R5", lens);

camera.capture();

camera.adjust(10);
camera.capture();

camera.adjust(-5);
camera.capture();
TypeScript

Example #2: Payment System

Let’s consider an online payment implementation for any e-commerce application. We are implementing payment processing systems like Stipe, Paypal, Card, etc.

Implementation using Inheritance (not recommended)

// Abstract Payment class
abstract class Payment {
    protected double amount;

    public Payment(double amount) {
        this.amount = amount;
    }

    public abstract void processPayment();
}

// StripePayment class
class StripePayment extends Payment {
    private String accountId;

    public StripePayment(String accountId, double amount) {
        super(amount);
        this.accountId = accountId;
    }

    @Override
    public void processPayment() {
        System.out.println("Processing Stripe Payment, with account id " + accountId + ", amount " + amount);
    }
}

// PayPalPayment class
class PayPalPayment extends Payment {
    private String email;

    public PayPalPayment(String email, double amount) {
        super(amount);
        this.email = email;
    }

    @Override
    public void processPayment() {
        System.out.println("Processing PayPal Payment, with email address " + email + ", amount " + amount);
    }
}

// CardPayment class
class CardPayment extends Payment {
    private String cardNumber;
    private String cvv;

    public CardPayment(String cardNumber, String cvv, double amount) {
        super(amount);
        this.cardNumber = cardNumber;
        this.cvv = cvv;
    }

    @Override
    public void processPayment() {
        System.out.println("Processing Card Payment with card number " + cardNumber + ", amount " + amount);
    }
}

// Demo Usage
public class Main {
    public static void main(String[] args) {
        StripePayment stripePayment = new StripePayment("test-acc-2929834", 100.0);
        stripePayment.processPayment();

        CardPayment cardPayment = new CardPayment("3700 0000 0000 002", "123", 5000.0);
        cardPayment.processPayment();
    }
}
Java
from abc import ABC, abstractmethod


class Payment(ABC):
    def __init__(self, amount: float) -> None:
        self.amount = amount

    @abstractmethod
    def process_payment(self) -> None:
        pass


class StripePayment(Payment):
    def __init__(self, account_id: int, amount: float) -> None:
        super().__init__(amount)

        self.account_id = account_id

    def process_payment(self) -> None:
        print(
            f"Processing Stripe Payment, with account id {self.account_id}, amount {self.amount}"
        )


class PayPalPayment(Payment):
    def __init__(self, email: str, amount: float) -> None:
        super().__init__(amount)

        self.email = email

    def process_payment(self) -> None:
        print(
            f"Processing PayPal Payment, with email address {self.email}, amount {self.amount}"
        )


class CardPayment(Payment):
    def __init__(self, card_number: str, cvv: str, amount: float) -> None:
        super().__init__(amount)

        self.card_number = card_number
        self.cvv = cvv

    def process_payment(self) -> None:
        print(
            f"Processing Card Payment with card number {self.card_number}, amount {self.amount}"
        )


# Usage demo
stripe_payment = StripePayment("test-acc-2929834", 100.0)
stripe_payment.process_payment()


card_payment = CardPayment(card_number="3700 0000 0000 002", cvv="123", amount=5_000.0)
card_payment.process_payment()
Python
package main

import "fmt"

// Payment interface
type Payment interface {
    ProcessPayment()
}

// StripePayment struct
type StripePayment struct {
    AccountID string
    Amount    float64
}

func (s *StripePayment) ProcessPayment() {
    fmt.Printf("Processing Stripe Payment, with account id %s, amount %.2f\n", s.AccountID, s.Amount)
}

// PayPalPayment struct
type PayPalPayment struct {
    Email  string
    Amount float64
}

func (p *PayPalPayment) ProcessPayment() {
    fmt.Printf("Processing PayPal Payment, with email address %s, amount %.2f\n", p.Email, p.Amount)
}

// CardPayment struct
type CardPayment struct {
    CardNumber string
    CVV        string
    Amount     float64
}

func (c *CardPayment) ProcessPayment() {
    fmt.Printf("Processing Card Payment with card number %s, amount %.2f\n", c.CardNumber, c.Amount)
}

// Demo usage
func main() {
    stripePayment := StripePayment{"test-acc-2929834", 100.0}
    stripePayment.ProcessPayment()

    cardPayment := CardPayment{"3700 0000 0000 002", "123", 5000.0}
    cardPayment.ProcessPayment()
}
Go
<?php

// Abstract Payment class
abstract class Payment {
    protected $amount;

    public function __construct($amount) {
        $this->amount = $amount;
    }

    abstract public function processPayment();
}

// StripePayment class
class StripePayment extends Payment {
    private $accountId;

    public function __construct($accountId, $amount) {
        parent::__construct($amount);
        $this->accountId = $accountId;
    }

    public function processPayment() {
        echo "Processing Stripe Payment, with account id {$this->accountId}, amount {$this->amount}\n";
    }
}

// PayPalPayment class
class PayPalPayment extends Payment {
    private $email;

    public function __construct($email, $amount) {
        parent::__construct($amount);
        $this->email = $email;
    }

    public function processPayment() {
        echo "Processing PayPal Payment, with email address {$this->email}, amount {$this->amount}\n";
    }
}

// CardPayment class
class CardPayment extends Payment {
    private $cardNumber;
    private $cvv;

    public function __construct($cardNumber, $cvv, $amount) {
        parent::__construct($amount);
        $this->cardNumber = $cardNumber;
        $this->cvv = $cvv;
    }

    public function processPayment() {
        echo "Processing Card Payment with card number {$this->cardNumber}, amount {$this->amount}\n";
    }
}

// Demo Usage
$stripePayment = new StripePayment('test-acc-2929834', 100.0);
$stripePayment->processPayment();

$cardPayment = new CardPayment('3700 0000 0000 002', '123', 5000.0);
$cardPayment->processPayment();
PHP
// Abstract Payment class
abstract class Payment {
    protected amount: number;

    constructor(amount: number) {
        this.amount = amount;
    }

    abstract processPayment(): void;
}

// StripePayment class
class StripePayment extends Payment {
    private accountId: string;

    constructor(accountId: string, amount: number) {
        super(amount);
        this.accountId = accountId;
    }

    processPayment(): void {
        console.log(`Processing Stripe Payment, with account id ${this.accountId}, amount ${this.amount}`);
    }
}

// PayPalPayment class
class PayPalPayment extends Payment {
    private email: string;

    constructor(email: string, amount: number) {
        super(amount);
        this.email = email;
    }

    processPayment(): void {
        console.log(`Processing PayPal Payment, with email address ${this.email}, amount ${this.amount}`);
    }
}

// CardPayment class
class CardPayment extends Payment {
    private cardNumber: string;
    private cvv: string;

    constructor(cardNumber: string, cvv: string, amount: number) {
        super(amount);
        this.cardNumber = cardNumber;
        this.cvv = cvv;
    }

    processPayment(): void {
        console.log(`Processing Card Payment with card number ${this.cardNumber}, amount ${this.amount}`);
    }
}

// Demo usage
const stripePayment = new StripePayment("test-acc-2929834", 100.0);
stripePayment.processPayment();

const cardPayment = new CardPayment("3700 0000 0000 002", "123", 5000.0);
cardPayment.processPayment();
TypeScript

Implementation using Composition (recommended)

// Payment interfaces and classes
interface PaymentMethod {
    void processPayment();
}

class StripePayment implements PaymentMethod {
    private String accountId;
    private double amount;

    public StripePayment(String accountId, double amount) {
        this.accountId = accountId;
        this.amount = amount;
    }

    @Override
    public void processPayment() {
        System.out.println("Processing Stripe Payment, with account id " + accountId + ", amount " + amount);
    }
}

class PayPalPayment implements PaymentMethod {
    private String email;
    private double amount;

    public PayPalPayment(String email, double amount) {
        this.email = email;
        this.amount = amount;
    }

    @Override
    public void processPayment() {
        System.out.println("Processing PayPal Payment, with email address " + email + ", amount " + amount);
    }
}

class CardPayment implements PaymentMethod {
    private String cardNumber;
    private String cvv;
    private double amount;

    public CardPayment(String cardNumber, String cvv, double amount) {
        this.cardNumber = cardNumber;
        this.cvv = cvv;
        this.amount = amount;
    }

    @Override
    public void processPayment() {
        System.out.println("Processing Card Payment with card number " + cardNumber + ", amount " + amount);
    }
}

// Payment Processor class
class PaymentProcessor {
    private PaymentMethod paymentMethod;

    public PaymentProcessor(PaymentMethod paymentMethod) {
        this.paymentMethod = paymentMethod;
    }

    public void process() {
        paymentMethod.processPayment();
    }

    public void setPaymentMethod(PaymentMethod newPaymentMethod) {
        this.paymentMethod = newPaymentMethod;
    }
}

// Demo Usage
public class Main {
    public static void main(String[] args) {
        PaymentProcessor processor = new PaymentProcessor(new StripePayment("test-acc-2929834", 100.0));
        processor.process();

        processor.setPaymentMethod(new CardPayment("3700 0000 0000 002", "123", 5000.0));
        processor.process();
    }
}
Java
class StripePayment:
    def __init__(self, account_id: int, amount: float) -> None:
        self.account_id = account_id
        self.amount = amount

    def process_payment(self) -> None:
        print(
            f"Processing Stripe Payment, with account id {self.account_id}, amount {self.amount}"
        )


class PayPalPayment:
    def __init__(self, email: str, amount: float) -> None:
        self.email = email
        self.amount = amount

    def process_payment(self) -> None:
        print(
            f"Processing PayPal Payment, with email address {self.email}, amount {self.amount}"
        )


class CardPayment:
    def __init__(self, card_number: str, cvv: str, amount: float) -> None:
        self.card_number = card_number
        self.cvv = cvv
        self.amount = amount

    def process_payment(self) -> None:
        print(
            f"Processing Card Payment with card number {self.card_number}, amount {self.amount}"
        )


class PaymentProcessor:
    def __init__(self, payment_method) -> None:
        self.payment_method = payment_method

    def process(self):
        return self.payment_method.process_payment()

    def set_payment_method(self, new_payment_method):
        self.payment_method = new_payment_method


# Usage demo
stripe_payment = StripePayment("test-acc-2929834", 100.0)
processor = PaymentProcessor(stripe_payment)
processor.process()

card_payment = CardPayment(card_number="3700 0000 0000 002", cvv="123", amount=5_000.0)
processor.set_payment_method(card_payment)
processor.process()
Python
package main

import "fmt"

// PaymentMethod interface
type PaymentMethod interface {
    ProcessPayment()
}

// StripePayment struct
type StripePayment struct {
    AccountID string
    Amount    float64
}

func (s *StripePayment) ProcessPayment() {
    fmt.Printf("Processing Stripe Payment, with account id %s, amount %.2f\n", s.AccountID, s.Amount)
}

// PayPalPayment struct
type PayPalPayment struct {
    Email  string
    Amount float64
}

func (p *PayPalPayment) ProcessPayment() {
    fmt.Printf("Processing PayPal Payment, with email address %s, amount %.2f\n", p.Email, p.Amount)
}

// CardPayment struct
type CardPayment struct {
    CardNumber string
    CVV        string
    Amount     float64
}

func (c *CardPayment) ProcessPayment() {
    fmt.Printf("Processing Card Payment with card number %s, amount %.2f\n", c.CardNumber, c.Amount)
}

// PaymentProcessor struct
type PaymentProcessor struct {
    PaymentMethod PaymentMethod
}

func (p *PaymentProcessor) Process() {
    p.PaymentMethod.ProcessPayment()
}

func (p *PaymentProcessor) SetPaymentMethod(newPaymentMethod PaymentMethod) {
    p.PaymentMethod = newPaymentMethod
}

// Demo usage
func main() {
    stripePayment := &StripePayment{"test-acc-2929834", 100.0}
    processor := &PaymentProcessor{stripePayment}
    processor.Process()

    cardPayment := &CardPayment{"3700 0000 0000 002", "123", 5000.0}
    processor.SetPaymentMethod(cardPayment)
    processor.Process()
}
Go
<?php

// PaymentMethod interface
interface PaymentMethod {
    public function processPayment();
}

// StripePayment class
class StripePayment implements PaymentMethod {
    private $accountId;
    private $amount;

    public function __construct($accountId, $amount) {
        $this->accountId = $accountId;
        $this->amount = $amount;
    }

    public function processPayment() {
        echo "Processing Stripe Payment, with account id {$this->accountId}, amount {$this->amount}\n";
    }
}

// PayPalPayment class
class PayPalPayment implements PaymentMethod {
    private $email;
    private $amount;

    public function __construct($email, $amount) {
        $this->email = $email;
        $this->amount = $amount;
    }

    public function processPayment() {
        echo "Processing PayPal Payment, with email address {$this->email}, amount {$this->amount}\n";
    }
}

// CardPayment class
class CardPayment implements PaymentMethod {
    private $cardNumber;
    private $cvv;
    private $amount;

    public function __construct($cardNumber, $cvv, $amount) {
        $this->cardNumber = $cardNumber;
        $this->cvv = $cvv;
        $this->amount = $amount;
    }

    public function processPayment() {
        echo "Processing Card Payment with card number {$this->cardNumber}, amount {$this->amount}\n";
    }
}

// PaymentProcessor class
class PaymentProcessor {
    private $paymentMethod;

    public function __construct($paymentMethod) {
        $this->paymentMethod = $paymentMethod;
    }

    public function process() {
        return $this->paymentMethod->processPayment();
    }

    public function setPaymentMethod($newPaymentMethod) {
        $this->paymentMethod = $newPaymentMethod;
    }
}

// Demo usage
$stripePayment = new StripePayment('test-acc-2929834', 100.0);
$processor = new PaymentProcessor($stripePayment);
$processor->process();

$cardPayment = new CardPayment('3700 0000 0000 002', '123', 5000.0);
$processor->setPaymentMethod($cardPayment);
$processor->process();
PHP
// PaymentMethod interface
interface PaymentMethod {
    processPayment(): void;
}

// StripePayment class
class StripePayment implements PaymentMethod {
    private accountId: string;
    private amount: number;

    constructor(accountId: string, amount: number) {
        this.accountId = accountId;
        this.amount = amount;
    }

    processPayment(): void {
        console.log(`Processing Stripe Payment, with account id ${this.accountId}, amount ${this.amount}`);
    }
}

// PayPalPayment class
class PayPalPayment implements PaymentMethod {
    private email: string;
    private amount: number;

    constructor(email: string, amount: number) {
        this.email = email;
        this.amount = amount;
    }

    processPayment(): void {
        console.log(`Processing PayPal Payment, with email address ${this.email}, amount ${this.amount}`);
    }
}

// CardPayment class
class CardPayment implements PaymentMethod {
    private cardNumber: string;
    private cvv: string;
    private amount: number;

    constructor(cardNumber: string, cvv: string, amount: number) {
        this.cardNumber = cardNumber;
        this.cvv = cvv;
        this.amount = amount;
    }

    processPayment(): void {
        console.log(`Processing Card Payment with card number ${this.cardNumber}, amount ${this.amount}`);
    }
}

// PaymentProcessor class
class PaymentProcessor {
    private paymentMethod: PaymentMethod;

    constructor(paymentMethod: PaymentMethod) {
        this.paymentMethod = paymentMethod;
    }

    process(): void {
        this.paymentMethod.processPayment();
    }

    setPaymentMethod(newPaymentMethod: PaymentMethod): void {
        this.paymentMethod = newPaymentMethod;
    }
}

// Demo usage
const stripePayment = new StripePayment("test-acc-2929834", 100.0);
const processor = new PaymentProcessor(stripePayment);
processor.process();

const cardPayment = new CardPayment("3700 0000 0000 002", "123", 5000.0);
processor.setPaymentMethod(cardPayment);
processor.process();
TypeScript

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.