← Назад к вопросам

По какому принципу объединяются методы в интерфейсах?

2.0 Middle🔥 131 комментариев
#Архитектура и паттерны#ООП

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Principi grupisanja metoda u interfejsima

Grupisanje metoda u interfejse je kriticno za dobru arhitekturu koda. Sahibice se vodi principom IS-A (je/je tip), a ne principom HAS-A (ima).

Osnovni principi grupisanja

1. Interface Segregation Principle (ISP)

Iz SOLID principi: "Klijenti ne bi trebalo da budu prisiljeni da zavise od interfejsa koji ne koriste."

Znaci: Ne kombinuj neurobličite metode u jedan interfejs.

// LOSE - preveliki interfejs
interface WorkerInterface {
    public function work(): void;
    public function eat(): void;
    public function sleep(): void;
    public function think(): void;
    public function manage(): void;
}

// Robot ne treba eat(), sleep(), think()
class Robot implements WorkerInterface {
    public function work(): void { /* ... */ }
    public function eat(): void { /* nema smisla */ }
    public function sleep(): void { /* nema smisla */ }
    public function think(): void { /* nema smisla */ }
    public function manage(): void { /* nema smisla */ }
}

// DOBRO - mali, fokusirani interfejsi
interface WorkableInterface {
    public function work(): void;
}

interface EatableInterface {
    public function eat(): void;
}

interface ManageableInterface {
    public function manage(): void;
}

class Human implements WorkableInterface, EatableInterface, ManageableInterface {
    public function work(): void { /* ... */ }
    public function eat(): void { /* ... */ }
    public function manage(): void { /* ... */ }
}

class Robot implements WorkableInterface {
    public function work(): void { /* ... */ }
}

2. Ulogocentrican pristup

Meotde se grupisavaju prema ULOGAMA koje objekti igraju:

interface PaymentProcessorInterface {
    public function charge(Money $amount): TransactionId;
    public function refund(TransactionId $id): bool;
}

interface AuthenticatableInterface {
    public function authenticate(string $credentials): bool;
    public function getToken(): string;
}

interface LoggableInterface {
    public function log(string $message): void;
    public function getLogs(): array;
}

class PaymentService implements PaymentProcessorInterface {
    public function charge(Money $amount): TransactionId { /* ... */ }
    public function refund(TransactionId $id): bool { /* ... */ }
}

class UserService implements AuthenticatableInterface, LoggableInterface {
    public function authenticate(string $credentials): bool { /* ... */ }
    public function getToken(): string { /* ... */ }
    public function log(string $message): void { /* ... */ }
    public function getLogs(): array { /* ... */ }
}

3. Kohezija - Povezanost metoda

Metode u interfejsu trebalo bi da budu jako povezane i da čine logičnu celinu:

// LOSE - niskohezivni interfejs
interface MixedInterface {
    public function getUserName(): string; // User operacija
    public function processPayment(Money $m): bool; // Payment operacija
    public function sendEmail(string $to): void; // Email operacija
}

// DOBRO - visokoheizivni interfejsi
interface UserRepositoryInterface {
    public function findById(int $id): User;
    public function findByEmail(string $email): ?User;
    public function save(User $user): void;
    public function delete(User $user): void;
}

interface PaymentGatewayInterface {
    public function charge(Money $amount): TransactionId;
    public function refund(TransactionId $id): bool;
    public function validate(PaymentMethod $method): bool;
}

interface EmailServiceInterface {
    public function send(Email $email): bool;
    public function queue(Email $email): void;
    public function sendBatch(array $emails): int;
}

4. Jednokratnost (Single Responsibility)

Svaki interfejs treba da odgovora na jedno pitanje ili deli jednu odgovornost:

// LOSE - previše odgovornosti
interface UserInterface {
    // Identifikacija
    public function getId(): int;
    public function getEmail(): string;
    
    // Validacija
    public function isValid(): bool;
    public function validate(): void;
    
    // Persistencija
    public function save(): void;
    public function delete(): void;
    
    // Notifikacija
    public function notify(): void;
}

// DOBRO - odvajanje odgovornosti
interface UserInterface {
    public function getId(): int;
    public function getEmail(): string;
}

interface ValidatorInterface {
    public function isValid(User $user): bool;
    public function validate(User $user): void;
}

interface RepositoryInterface {
    public function save(User $user): void;
    public function delete(User $user): void;
}

interface NotifierInterface {
    public function notify(User $user): void;
}

5. Dependency Inversion Principle (DIP)

Zavisimo od apstrakcija, a ne od konkretnih implementacija. Interfejsi se grupisavaju tako da omoguce fleksibilnost:

// LOSE - zavisi od konkretne implementacije
class OrderService {
    private StripePaymentGateway $gateway;
    
    public function __construct() {
        $this->gateway = new StripePaymentGateway();
    }
}

// DOBRO - zavisi od interfejsa
interface PaymentGatewayInterface {
    public function charge(Money $amount): TransactionId;
    public function refund(TransactionId $id): bool;
}

class OrderService {
    public function __construct(
        private PaymentGatewayInterface $gateway
    ) {}
    
    public function processOrder(Order $order): void {
        $this->gateway->charge($order->getTotal());
    }
}

// Sada se lako zamenjuje:
class StripePaymentGateway implements PaymentGatewayInterface { /* ... */ }
class PayPalPaymentGateway implements PaymentGatewayInterface { /* ... */ }
class BitcoinPaymentGateway implements PaymentGatewayInterface { /* ... */ }

6. Taga (Tags) - grupisanje po svrsi

Meotode se grupisavaju po domenu ili svrsi:

// E-commerce domen
interface CartInterface {
    public function addItem(Product $product, int $qty): void;
    public function removeItem(Product $product): void;
    public function getTotal(): Money;
    public function getItems(): array;
}

interface CheckoutInterface {
    public function initiate(Cart $cart): Checkout;
    public function setShippingAddress(Address $addr): void;
    public function setPaymentMethod(PaymentMethod $pm): void;
    public function complete(): Order;
}

interface OrderFulfillmentInterface {
    public function ship(Order $order): void;
    public function track(Order $order): string;
    public function cancel(Order $order): void;
}

Prakticni primer - dobar dizajn

// Pravac 1: Skladiste/Readiness
interface UserRepositoryInterface {
    public function findById(int $id): ?User;
    public function findByEmail(string $email): ?User;
    public function save(User $user): void;
    public function delete(User $user): void;
}

// Pravac 2: Autentifikacija
interface AuthServiceInterface {
    public function login(string $email, string $password): Token;
    public function logout(Token $token): void;
    public function refreshToken(Token $token): Token;
}

// Pravac 3: Autorizacija
interface AuthorizationServiceInterface {
    public function can(User $user, string $action, mixed $resource): bool;
    public function authorize(User $user, string $action, mixed $resource): void;
}

// Pravac 4: Validacija
interface UserValidatorInterface {
    public function validateEmail(string $email): bool;
    public function validatePassword(string $password): bool;
    public function validate(User $user): array; // Greske
}

// Sada je jasno KUDU ide svaka metoda
// Interfejsi su mali i fokusirani
// Lako je testirati svaki interfejs odvojeno

Antipaterni - šta izbegavati

// LOSE
interface MegaInterface {
    // 20+ metoda
    // Nema jasnog fokusa
    // Tesko je implementirati
    // Klase moraju da implementiraju sto ne koriste
}

// DOBRO
interface RepositoryInterface { /* 5-7 metoda */ }
interface ServiceInterface { /* 3-5 metoda */ }
interface FactoryInterface { /* 2-3 metoda */ }

Checklist za grupisanje metoda

  • Sve metode trebalo bi da budu povezane konceptualno
  • Interfejs treba da ima jasnu, jednu svrhu
  • Klijenti ne trebalo bi da budu prisiljeni da zavise od metoda koje ne koriste
  • Metode trebalo bi da budu na sličnom nivou apstrakcije
  • Interfejs bi trebalo da bude mali (3-7 metoda)

Zakljucak: Principi grupisanja metoda u interfejsima (ISP, single responsibility, cohesion) osiguravaju da kod bude fleksibilan, testabilan i lako održavan.