Summary
Principle Name | Composition Over Inheritance |
Acronym | COI |
Principle Type | Core Principle |
Purpose | Build 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();
}
}
Javaclass 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()
Pythonpackage 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();
PHPclass 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();
TypeScriptImplementation 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();
}
}
Javaclass 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()
Pythonpackage 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();
PHPclass 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();
TypeScriptExample #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();
}
}
Javafrom 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()
Pythonpackage 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();
TypeScriptImplementation 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();
}
}
Javaclass 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()
Pythonpackage 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