По какому принципу объединяются методы в интерфейсах?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
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.