L'accoppiamento tra classi di oggetti (CBO) è una metrica proposta da Chidamber & Kemerer per misurare per una classe quanto altre classi sono accoppiate. Un accoppiamento significa che un oggetto di una classe usa metodi o proprietà di un oggetto in un'altra classe.
Il fattore polimorfico (PF) è una metrica proposta da Abreu & Melo per misurare quanto un tipo derivato sostituisce un metodo dalla classe base. Viene calcolato contando il numero di metodi sottoposti a override rispetto al numero di metodi.
Queste sono misure indipendenti, quindi in teoria puoi trovare qualsiasi tipo di relazione. Ma diamo un'occhiata a un esempio per mostrare come si relazionano nella pratica.
Supponiamo di avere classi per rappresentare diverse forme ( Circle
, Square
, ecc ...) e una classe Figure
, composta da più forme. Figure
ha una funzione draw()
che richiama un metodo di disegno per ciascuna delle sue forme.
-
Implementazione Uggly : ogni forma come una propria classe indipendente con una propria funzione di disegno specifica (ad esempio
draw_circle()
, draw_square(
), ...). Figure
deve quindi essere abbinato a tutte le forme, con un sacco di condizionali per far fronte alle diverse forme. Ogni volta che aggiungi una nuova forma, aggiungi un nuovo accoppiamento.
- CBO = N, dove N è il numero di forme.
- PF = 0 perché non c'è ereditarietà e quindi non ha priorità.
-
Implementazione polimorfica: ogni forma eredita da una superclasse
Shape
e sovrascrive la funzione polimorfa draw()
. Figure
conosce solo Shape
.
- CBO = 1, perché
Figure
richiama solo draw()
su un oggetto Shape
.
- PF tende al 100% (precisamente è
N/(2+N)
perché Figure::draw()
e Shape::draw()
non sono overrides, ma Shape::draw()
è sovrascritto da N forme
L'ipotesi comune è che un sistema con accoppiamento basso sia più facile da mantenere. Pertanto, molti modelli di progettazione intendono ridurre l'accoppiamento. Nella maggior parte dei casi, il polimorfismo è il fattore abilitante per un disaccoppiamento.
L'astrazione è la chiave, non la funzione linguistica utilizzata per implementarla. L'ereditarietà dell'interfaccia e l'ereditarietà normale sono due modi per ottenere l'astrazione. L'ereditarietà dell'interfaccia richiede di fornire un'implementazione per le funzioni dell'interfaccia (vale a dire fornire un override per le funzioni astratte che non sono definite). Quindi aumenta matematicamente PF. Tuttavia, alcuni linguaggi come il C ++ non hanno interfacce ma usano pure funzioni virtuali alla fine con ereditarietà multipla per fare lo stesso, con un PF identico. Nel nostro esempio, l'ereditarietà è l'abilitazione per ridurre l'accoppiamento.