Responsabilità della classe base

0

la classe base può contenere metodi protetti che non devono essere usati da tutte le classi discendenti?

Ho questa situazione:

  • EntityA: ha alcuni metodi che gestiscono le attività
  • EntitàB: ha alcuni metodi che gestiscono i prodotti
  • EntityC: ha metodi che gestiscono sia le attività che i prodotti

Uso C #, quindi l'ereditarietà multipla non è possibile.

Va bene avere una classe base con metodi protetti che gestiscono sia le attività che i prodotti e che tutte e 3 le classi ereditino da questa classe base?

Modifica : non ho mai capito cosa guadagniamo usando invece la composizione, come implementare tale approccio in uno scenario più complesso. Lascia che ti dia una situazione un po 'più espansa:

  • EntityA: deve utilizzare internamente il metodo FilterActivitiesByType () e ha metodi pubbliciA1 (), A2 (), A3 ()
  • EntitàB: deve utilizzare internamente il metodo FilterProductsByType () e ha metodi pubblici B1 (), B2 (), B3 ()
  • EntityC: deve utilizzare internamente sia FilterActivitiesByType () che FilterProductsByType (), e ha metodi pubbliciC1 (), C2 (), C3 ()

Quindi, sia FilterActivitiesByType che FilterProductsByType non devono essere esposti attraverso l'interfaccia. Questi metodi possono in molti casi essere anche statici. Ora posso mettere questi due metodi rispettivamente nelle classi IFilterActivityHelper e IFilterProductHelper e utilizzare DI nel costruttore per renderlo disponibile alle classi EntityA, EntityB ed EntityC. Questo è, credo a ciò che tutti consigliate per composizione.

Ora immagina di avere diversi metodi di supporto alle attività e diversi metodi di supporto dei prodotti. Potrei inserirli in ciascuna classe di helper specifica (1a), oppure potrei inserire tutti i metodi helper di attività in una classe ActivityHelper (2a). (1 °) Significa che avrò un sacco di istanze da iniettare nel costruttore, per ogni metodo di aiuto separato. (2 °) Ci dà lo stesso situtation della mia domanda originale con ereditarietà, poiché ora IActivityHelper è stato inserito in ActivityA e ActivityA deve utilizzare solo 2 metodi su 5 che espone.

Quindi qualcuno può elaborare come eseguire correttamente la composizione in questi casi?

    
posta Goran 31.07.2018 - 12:54
fonte

3 risposte

5

Is it OK to have a base class with protected methods that deal with both activities and products, and have all 3 classes inherit from this base class?

No, non sarebbe male (tm).

Utilizza invece interfacce e composizione

public class EntityC : IActivities, IProducts
{
    private IActivities EntityA;
    private IProducts EntityB;

    public Activity GetActivity()
    {
        return this.EntityA.GetActivity();
    }

    public Product GetProduct()
    {
        return this.EntityB.GetProduct();
    }
}

Se crei una nuova classe base con tutte le funzionalità, diventerà sempre più grande finché non farà tutto.

Modifica post:

(1st) Means that I will have lots of instances to inject in constructor, for each separate helper method.

(2nd) Gives us the the same situtation as in my original question with inheritance, since I now have IActivityHelper inserted in ActivityA, and ActivityA needs to use only 2 methods out of 5 that it exposes.

Prima di tutto, non chiamarli 'Helpers'. Può sembrare un banale nitpick name, ma in realtà è la radice del problema.

Se chiami un Helper o un Manager di classe o qualcosa del genere, non hai idea di quali metodi dovrebbero essere utilizzati.

Disponi di un repository o di un filtro o di una ShoppingBag, quindi sai in quale classe deve essere inserito un nuovo metodo. Pensare al nome ti costringe a considerare la singola responsabilità di quella classe e ti fornirà classi di dimensioni ragionevoli con gruppi di metodi sensibili

    
risposta data 31.07.2018 - 13:12
fonte
0

Penso che quello che stai descrivendo sia FINE. Non c'è motivo per non farlo, ma ci sono alcuni problemi su come farlo.

Usi le interfacce per esprimere ciò che vuoi vedere esternamente, il tuo design. Tuttavia, puoi utilizzare ereditarietà per esprimere la condivisione del codice, soprattutto se utilizzi l'ereditarietà privata.

La chiave è definire INTERFACES per l'essenza di A-Activities e per l'essenza di B-Activities.

Quindi se hai un'implementazione di A e un'implementazione di B, che implementa tali interfacce.

E quindi puoi creare C, supportando le due interfacce. E se scegli di utilizzare l'ereditarietà privata o l'aggregazione, o qualche altro mezzo, è completamente la tua chiamata - qualunque sia la cosa più comoda.

interaceA {
  .... some methods;
};
interaceB {
  .... some methods;
};

ONE WAY:

class A1 : implement interaceA {
};
class B1 : implement interaceB {
};
class C1 : implements interface A, implements interfaceB {
  A a;
  B b;
 ....
};

UN ALTRO MODO RAGIONEVOLE:

spazio dei nomi privato {          class myhelper_: implementa A, implementa B {          ....          };    }

class A2 : implement interaceA , private::myhelper{
};
class B2 : implement interaceB, private::myhelper {
};
class C2 : implements interface A, implements interfaceB, private::myhelper {
 ....
};

EITHER way, hai catturato le tue due interfacce e il modo in cui le implementate è un dettaglio di implementazione nascosto.

    
risposta data 31.07.2018 - 15:43
fonte
0

Le interfacce e le classi base dovrebbero fornire una garanzia su come le istanze della tua classe possono essere interagite con. Essenzialmente, sono un meccanismo per il polimorfismo (in cui la classe base può anche fornire funzionalità e applicare restrizioni ai suoi discendenti). Questo non è ciò che stai cercando di ottenere qui, quindi non c'è motivo di preferire l'ereditarietà, quindi dovresti preferire la composizione.

La composizione ha almeno due vantaggi pertinenti a questo caso:

  • Puoi farlo più di una volta
  • Puoi scegliere quali parti degli oggetti composti usi effettivamente

Questo significa che puoi scegliere di avere un aiutante per le attività e un aiutante per i prodotti (dando uno a A, un altro a B, e entrambi a C). Oppure puoi scegliere di avere un aiuto per entrambe le attività e i prodotti (assegnandoli ad A, B, C), senza che nessuno al di fuori delle tue lezioni noti una differenza. Anche se la tua classe base non avrebbe un'interfaccia pubblica, avrebbe comunque effetto sui discendenti ipotetici di A, B e C, e ottenere l'accesso a quei metodi protetti significa che devi rinunciare a qualsiasi altra classe base che sarebbe utile.

Composition consente anche di usare l'iniezione delle dipendenze, che non è un'opzione quando si dipende dalla classe base. Tuttavia, puoi evitarlo se non ti è utile e creare internamente le istanze degli helper. Probabilmente sarà utile per testare se non altro. Se ti ritrovi a iniettare troppo, A, B e C probabilmente stanno facendo troppo. Se si desidera mantenere il codice client semplice, è possibile fornire costruttori predefiniti utilizzando le implementazioni di supporto predefinite.

    
risposta data 01.08.2018 - 15:45
fonte

Leggi altre domande sui tag