C'è qualcosa di sbagliato nell'avere una sola interfaccia da implementare più volte nella catena ereditaria?

6
interface IUser {}
interface IConcreteUser : IUser {}

abstract class UserBase : IUser {}

class ConcreteUser : UserBase, IConcreteUser {}

Come puoi vedere, ConcreteUser eredita IUser due volte - una volta ereditando da UserBase e secondo tempo implementando l'interfaccia IConcreteUser .

C'è qualcosa di sbagliato in questo? Mi sembra che dovrebbe segnalare una sorta di problema di progettazione, ma non ne sono sicuro.

    
posta Pavel T. 01.12.2016 - 16:39
fonte

5 risposte

1

Supponendo di poter sostituire ConcreteUser con AdminUser poiché è difficile pensare a questa domanda sono termini così generali ...

La vera risposta a questa domanda implica la decisione di base su come gli oggetti sono correlati (vedi link )

Una citazione copiata e incollata dalla risposta di cletus alla domanda StackOverflow:

This is object-oriented programming and UML terminology, not Java-specific. There are actually three cases you should be aware of:

  1. A House is a Building (inheritance);
  2. A House has a Room (composition);
  3. A House has an occupant (aggregation).

The difference between (2) and (3) is subtle yet important to differentiate. Together they are forms of association. What's the difference? Composition implies the child object cannot live out of the context of the parent (destroy the house and rooms disappear) whereas aggregation implies the child can exist on its own (destroy the house and the occupant goes elsewhere).

Pertanto, la risposta alla domanda tua implica la possibilità di porre le domande precedenti:

  1. Un utente amministratore è un utente? (ereditarietà) - Sì.

  2. Un utente ha un utente amministratore ? (composizione) - No.

  3. Un utente ha uno o più utenti amministratore? (aggregazione) - No.

In questo caso, penso che un utente amministratore sia un utente, quindi l'ereditarietà è corretta per le interfacce.

  1. UserBase an IUser ? Sì.

  2. UserBase an IAdmin ? No.

  3. AdminUser an IUser ? Sì.

  4. AdminUser an IAdmin ? Sì.

In questo caso, ereditare più volte la stessa interfaccia va bene.

    
risposta data 02.12.2016 - 14:45
fonte
4

Tecnicamente no. Non vi è alcun problema in una prospettiva di progettazione OO di alto livello. Questo genere di cose emerge molto quando si utilizzano classi astratte per fornire implementazioni predefinite di interfacce.

Penso che valga la pena ricordare che molte persone ti diranno di favorire la composizione sull'eredità. Mentre sono d'accordo, fornire una classe astratta come implementazione di default può essere utile (in una certa misura). Non ha una buona scalabilità, il che significa che funziona davvero bene solo con un livello di ereditarietà. Qualunque cosa al di là di questo e comincerà a essere un disordine aggrovigliato.

    
risposta data 01.12.2016 - 17:07
fonte
2

La cosa che spicca per me è l'interfaccia che eredita da un'altra interfaccia.

interface IConcreteUser : IUser {}

Trovo difficile immaginare la situazione in cui non sarebbe meglio dividere IConcreteUser in qualunque sia la sua funzionalità extra e l'IUser già esistente. Quindi avere la classe Concrete implementare entrambe le interfacce

interface IUser {
    bool Login();
}

interface IAdmin {
    bool RebootServer();
}

abstract class UserBase : IUser {}

class AdminUser : UserBase, IAdmin {}

In alternativa, se la funzionalità di amministrazione viene sempre utilizzata con la funzionalità Utente, ciò suggerisce che è meglio metterlo insieme in IUser.

Non dico che mai sia una cosa sensata da ereditare l'interfaccia. Ad esempio, potresti avere due tipi di oggetti che sono sia amministratori che utenti e desideri inserirli in un elenco

class AdminUser : IUser, IAdmin

class UserAdmin : IUser, IAdmin

List<INeedAnInterface> AdminUsers_and_UserAdmin;

Ma se sei in grado di cambiare le interfacce, puoi anche modificare l'ereditarietà degli oggetti.

class BaseUserAdmin : IUser, IAdmin

class AdminUser : BaseUserAdmin

class UserAdmin : BaseUserAdmin

Quindi credo che quello che sto dicendo sia, sì, il tuo codice sembra un po 'strano. Ma non rotto wierd

    
risposta data 01.12.2016 - 18:13
fonte
1

Non c'è alcun problema di progettazione apparente.

Si potrebbe temere di imbattersi nel "problema dei diamanti" nel contesto di eredità multipla . Ma questo apparirà solo nei linguaggi di programmazione in cui è consentita l'ereditarietà multipla (dell'implementazione), con solo più eredità interfaccia , come in Java o C #, non c'è modo di imbattersi nei soliti problemi di ambiguità.

    
risposta data 01.12.2016 - 17:06
fonte
1

Con le interfacce, no ... non c'è un problema perché le interfacce dichiarano solo metodi astratti e richiedono le implementazioni per fornire tali azioni.

Solo perché IConcreteUser è basato su IUser, si presume che IConcreteUser fornisca metodi aggiuntivi che lo definiscono come un'interfaccia unica.

    
risposta data 01.12.2016 - 17:38
fonte

Leggi altre domande sui tag