Separated Interface (Выделенный интерфейс)

Паттерн проектирования Separated Interface

Паттерн проектирования Separated Interface

Описание Separated Interface

Выделение какого-либо интерфейса к объекту в отдельный от объекта пакет

При разработке какой-либо системы, можно добиться улучшение её архитектуры, уменьшая связанность между её частями. Это можно сделать так - распределив классы по отдельным пакетам и контролировать зависимости этими пакетами. Тогда можно следовать правилам о том, как классы из одного пакета могут обращаться к классам из другого пакета. Например, то, которое запрещает классам с уровня данных обращаться к классам с уровня представления.

Тем не менее, может возникнуть необходимость реализовать методы, которые противоречат основной структуре зависимостей. В таком случае можно использовать Выделенный Интерфейс, чтобы определить какой-либо интерфейс в одном пакете, а реализовать в другом. Таким образом, любой клиент, которому нужна зависимость от этого интерфейса может совершенно не думать о реализации доступа. Паттерн Separated Interface (Выделенный Интерфейс) предоставляет хорошую точку подключения паттерна Gateway (Шлюз)

Примеры реализации

// Separated Interface Pattern in JavaScript
// Interface definition (separated from implementation)
class PaymentProcessor {
    processPayment(amount, currency) {
        throw new Error('Method must be implemented');
    }
}

// Implementation 1: Credit Card Processor
class CreditCardProcessor extends PaymentProcessor {
    constructor(apiKey) {
        super();
        this.apiKey = apiKey;
    }
    
    processPayment(amount, currency) {
        console.log(`Processing ${amount} ${currency} via Credit Card`);
        return { success: true, transactionId: `cc_${Date.now()}` };
    }
}

// Implementation 2: PayPal Processor
class PayPalProcessor extends PaymentProcessor {
    constructor(clientId, clientSecret) {
        super();
        this.clientId = clientId;
        this.clientSecret = clientSecret;
    }
    
    processPayment(amount, currency) {
        console.log(`Processing ${amount} ${currency} via PayPal`);
        return { success: true, transactionId: `pp_${Date.now()}` };
    }
}

// Implementation 3: Bank Transfer Processor
class BankTransferProcessor extends PaymentProcessor {
    constructor(bankCode) {
        super();
        this.bankCode = bankCode;
    }
    
    processPayment(amount, currency) {
        console.log(`Processing ${amount} ${currency} via Bank Transfer`);
        return { success: true, transactionId: `bt_${Date.now()}` };
    }
}

// Service that uses the interface
class PaymentService {
    constructor(processor) {
        this.processor = processor;
    }
    
    chargeCustomer(amount, currency) {
        return this.processor.processPayment(amount, currency);
    }
}

// Usage
const creditCardProcessor = new CreditCardProcessor('cc_api_key');
const paypalProcessor = new PayPalProcessor('pp_client_id', 'pp_secret');
const bankProcessor = new BankTransferProcessor('bank_001');

const paymentService1 = new PaymentService(creditCardProcessor);
const paymentService2 = new PaymentService(paypalProcessor);
const paymentService3 = new PaymentService(bankProcessor);

// All services use the same interface
console.log(paymentService1.chargeCustomer(100, 'USD'));
console.log(paymentService2.chargeCustomer(50, 'EUR'));
console.log(paymentService3.chargeCustomer(200, 'GBP'));
<?php
// Separated Interface Pattern in PHP
// Interface definition (separated from implementation)
interface PaymentProcessor {
    public function processPayment($amount, $currency);
}

// Implementation 1: Credit Card Processor
class CreditCardProcessor implements PaymentProcessor {
    private $apiKey;
    
    public function __construct($apiKey) {
        $this->apiKey = $apiKey;
    }
    
    public function processPayment($amount, $currency) {
        echo "Processing $amount $currency via Credit Card\n";
        return ['success' => true, 'transactionId' => 'cc_' . time()];
    }
}

// Implementation 2: PayPal Processor
class PayPalProcessor implements PaymentProcessor {
    private $clientId;
    private $clientSecret;
    
    public function __construct($clientId, $clientSecret) {
        $this->clientId = $clientId;
        $this->clientSecret = $clientSecret;
    }
    
    public function processPayment($amount, $currency) {
        echo "Processing $amount $currency via PayPal\n";
        return ['success' => true, 'transactionId' => 'pp_' . time()];
    }
}

// Implementation 3: Bank Transfer Processor
class BankTransferProcessor implements PaymentProcessor {
    private $bankCode;
    
    public function __construct($bankCode) {
        $this->bankCode = $bankCode;
    }
    
    public function processPayment($amount, $currency) {
        echo "Processing $amount $currency via Bank Transfer\n";
        return ['success' => true, 'transactionId' => 'bt_' . time()];
    }
}

// Service that uses the interface
class PaymentService {
    private $processor;
    
    public function __construct(PaymentProcessor $processor) {
        $this->processor = $processor;
    }
    
    public function chargeCustomer($amount, $currency) {
        return $this->processor->processPayment($amount, $currency);
    }
}

// Usage
$creditCardProcessor = new CreditCardProcessor('cc_api_key');
$paypalProcessor = new PayPalProcessor('pp_client_id', 'pp_secret');
$bankProcessor = new BankTransferProcessor('bank_001');

$paymentService1 = new PaymentService($creditCardProcessor);
$paymentService2 = new PaymentService($paypalProcessor);
$paymentService3 = new PaymentService($bankProcessor);

// All services use the same interface
$result1 = $paymentService1->chargeCustomer(100, 'USD');
$result2 = $paymentService2->chargeCustomer(50, 'EUR');
$result3 = $paymentService3->chargeCustomer(200, 'GBP');

echo "Result 1: " . json_encode($result1) . "\n";
echo "Result 2: " . json_encode($result2) . "\n";
echo "Result 3: " . json_encode($result3) . "\n";
?>
// Separated Interface Pattern in Go
package main

import (
    "fmt"
    "time"
)

// Interface definition (separated from implementation)
type PaymentProcessor interface {
    ProcessPayment(amount float64, currency string) map[string]interface{}
}

// Implementation 1: Credit Card Processor
type CreditCardProcessor struct {
    ApiKey string
}

func (ccp CreditCardProcessor) ProcessPayment(amount float64, currency string) map[string]interface{} {
    fmt.Printf("Processing %.2f %s via Credit Card\n", amount, currency)
    return map[string]interface{}{
        "success":       true,
        "transactionId": fmt.Sprintf("cc_%d", time.Now().Unix()),
    }
}

// Implementation 2: PayPal Processor
type PayPalProcessor struct {
    ClientId     string
    ClientSecret string
}

func (ppp PayPalProcessor) ProcessPayment(amount float64, currency string) map[string]interface{} {
    fmt.Printf("Processing %.2f %s via PayPal\n", amount, currency)
    return map[string]interface{}{
        "success":       true,
        "transactionId": fmt.Sprintf("pp_%d", time.Now().Unix()),
    }
}

// Implementation 3: Bank Transfer Processor
type BankTransferProcessor struct {
    BankCode string
}

func (btp BankTransferProcessor) ProcessPayment(amount float64, currency string) map[string]interface{} {
    fmt.Printf("Processing %.2f %s via Bank Transfer\n", amount, currency)
    return map[string]interface{}{
        "success":       true,
        "transactionId": fmt.Sprintf("bt_%d", time.Now().Unix()),
    }
}

// Service that uses the interface
type PaymentService struct {
    processor PaymentProcessor
}

func NewPaymentService(processor PaymentProcessor) *PaymentService {
    return &PaymentService{processor: processor}
}

func (ps *PaymentService) ChargeCustomer(amount float64, currency string) map[string]interface{} {
    return ps.processor.ProcessPayment(amount, currency)
}

// Usage
func main() {
    creditCardProcessor := CreditCardProcessor{ApiKey: "cc_api_key"}
    paypalProcessor := PayPalProcessor{ClientId: "pp_client_id", ClientSecret: "pp_secret"}
    bankProcessor := BankTransferProcessor{BankCode: "bank_001"}

    paymentService1 := NewPaymentService(creditCardProcessor)
    paymentService2 := NewPaymentService(paypalProcessor)
    paymentService3 := NewPaymentService(bankProcessor)

    // All services use the same interface
    result1 := paymentService1.ChargeCustomer(100.0, "USD")
    result2 := paymentService2.ChargeCustomer(50.0, "EUR")
    result3 := paymentService3.ChargeCustomer(200.0, "GBP")

    fmt.Printf("Result 1: %+v\n", result1)
    fmt.Printf("Result 2: %+v\n", result2)
    fmt.Printf("Result 3: %+v\n", result3)
}

Использована иллюстрация с сайта Мартина Фаулера.

Источник