Usa la classe astratta in C # come definizione

21

Come sviluppatore C ++ sono abbastanza abituato ai file header C ++ e trovo utile avere una sorta di "documentazione" forzata all'interno del codice. Di solito ho un brutto periodo in cui devo leggere un codice C # per questo: non ho quel tipo di mappa mentale della classe con cui sto lavorando.

Supponiamo che come ingegnere del software sto progettando il framework di un programma. Sarebbe troppo folle definire ogni classe come una classe astratta non implementata, in modo simile a ciò che faremmo con le intestazioni C ++ e consentire agli sviluppatori di implementarla?

Immagino che ci possano essere dei motivi per cui qualcuno potrebbe trovare che questa sia una soluzione terribile, ma non sono sicuro del perché. Cosa si dovrebbe prendere in considerazione per una soluzione come questa?

    
posta Dani Barca Casafont 24.01.2018 - 15:53
fonte

4 risposte

44

Il motivo per cui questo è stato fatto in C ++ ha avuto a che fare con la realizzazione di compilatori più veloci e facili da implementare. Questo non era un progetto per semplificare la programmazione .

Lo scopo dei file di intestazione era di consentire al compilatore di eseguire un primo passaggio super veloce per conoscere tutti i nomi delle funzioni attese e allocare le posizioni di memoria per loro in modo che possano essere referenziati quando chiamati nei file cp, anche se la classe la loro definizione non era ancora stata analizzata.

Non è consigliabile provare a replicare una conseguenza dei vecchi limiti hardware in un moderno ambiente di sviluppo!

Definire un'interfaccia o una classe astratta per ogni classe ridurrà la tua produttività; cos'altro hai potuto fare con quel tempo ? Inoltre, altri sviluppatori non seguiranno questa convenzione.

In effetti, altri sviluppatori potrebbero eliminare le tue classi astratte. Se trovo un'interfaccia nel codice che soddisfi entrambi i criteri, la elimini e la rifattiamo fuori codice: 1. Does not conform to the interface segregation principle 2. Only has one class that inherits from it

L'altra cosa è che ci sono strumenti inclusi in Visual Studio che fanno ciò che si mira a realizzare automaticamente:

  1. Il Class View
  2. Il Object Browser
  3. In Solution Explorer puoi fare clic sui triangoli per utilizzare le classi per visualizzarne funzioni, parametri e tipi di ritorno.
  4. Ci sono tre piccoli menu a discesa sotto le schede dei file, il più a destra elenca tutti i membri della classe corrente.

Fornisci una prova prima di dedicare del tempo a replicare i file di intestazione C ++ in C #.

Inoltre, ci sono ragioni tecniche per non farlo ... renderà il tuo binario finale più grande di quanto non debba essere. Ripeterò questo commento di Mark Benningfield:

Declarations in C++ header files don't end up being part of the generated binary. They are there for the compiler and linker. These C# abstract classes would be part of the generated code, to no benefit whatsoever.

Inoltre, citato da Robert Harvey, tecnicamente, l'equivalente più vicino di un'intestazione in C # sarebbe un'interfaccia, non una classe astratta.

    
risposta data 24.01.2018 - 16:27
fonte
14

In primo luogo, comprendi che una classe puramente astratta è in realtà solo un'interfaccia che non può fare eredità multiple.

Scrivi classe, estrai un'interfaccia, è un'attività cerebrale morta. Tanto che abbiamo un refactoring per questo. Che è un peccato Seguendo questo schema "ogni classe ottiene un'interfaccia" non solo produce disordine, ma manca completamente il punto.

Un'interfaccia non dovrebbe essere pensata semplicemente come una riaffermazione formale di ciò che la classe può fare. Un'interfaccia dovrebbe essere pensata come un contratto imposto dall'uso del codice client che dettaglia le sue esigenze.

Non ho alcun problema a scrivere un'interfaccia che al momento ha solo una classe che la implementa. In realtà non mi interessa se nessuna classe lo implementa ancora. Perché sto pensando a ciò che il mio codice usa ha bisogno. L'interfaccia esprime ciò che richiede il codice usando. Qualunque cosa succeda più tardi può fare ciò che vuole fintanto che soddisfa queste aspettative.

Ora non lo faccio ogni volta che un oggetto ne usa un altro. Lo faccio quando valico un confine. Lo faccio quando non voglio che un oggetto sappia esattamente a quale altro oggetto sta parlando. Qual è l'unico modo in cui il polimorfismo funzionerà. Lo faccio quando mi aspetto che l'oggetto con cui sta parlando il mio codice cliente possa cambiare. Certamente non lo faccio quando quello che sto usando è la classe String. La classe String è bella e stabile e non ho bisogno di guardarmi dal cambiare su di me.

Quando decidi di interagire direttamente con un'implementazione concreta piuttosto che attraverso un'astrazione, prevedi che l'implementazione sia abbastanza stabile da non dover cambiare.

Questo è il modo in cui modifico il principio di inversione delle dipendenze . Non dovresti applicarlo alla cieca in modo fanatico a tutto. Quando aggiungi un'astrazione, stai dicendo che non ti fidi della scelta della classe di implementazione di essere stabile per tutta la durata del progetto.

Tutto presuppone che tu stia cercando di seguire il Open Closed Principle . Questo principio è importante solo quando i costi associati a modifiche dirette al codice stabilito sono significativi. Uno dei motivi principali per cui le persone non sono d'accordo su quanto sia importante il disaccoppiamento degli oggetti è perché non tutti sperimentano gli stessi costi quando fanno cambiamenti diretti. Se ritestare, ricompilare e ridistribuire l'intero codice base è banale per te allora risolvere una necessità di cambiamento con la modifica diretta è probabilmente una semplificazione molto interessante di questo problema.

Semplicemente non c'è una risposta cerebrale a questa domanda. Un'interfaccia o una classe astratta non è qualcosa che dovresti aggiungere ad ogni classe e non puoi semplicemente contare il numero di classi di implementazione e decidere che non è necessario. Si tratta di affrontare il cambiamento. Il che significa che stai anticipando il futuro. Non essere sorpreso se ti sbagli. Mantieni il più semplice possibile senza arroccarti in un angolo.

Quindi, per favore, non scrivere astrazioni solo per aiutarci a leggere il codice. Abbiamo strumenti per questo. Usa le astrazioni per disaccoppiare ciò che ha bisogno di disaccoppiare.

    
risposta data 24.01.2018 - 17:02
fonte
5

Sì, sarebbe terribile perché (1) Introduce codice non necessario (2) Confonderà il lettore.

Se vuoi programmare in C # dovresti solo abituarti a leggere C #. Il codice scritto da altre persone non seguirà comunque questo modello.

    
risposta data 24.01.2018 - 16:04
fonte
1

Test unitari

Suggerisco caldamente di scrivere test unitari invece di ingombrare il codice con interfacce o classi astratte (eccetto dove giustificato per altri motivi).

Un test unitario ben scritto non descrive solo l'interfaccia della classe (come un file di intestazione, una classe astratta o un'interfaccia), ma descrive anche, ad esempio, la funzionalità desiderata.

Esempio: dove potresti aver scritto un file di intestazione myclass.h in questo modo:

class MyClass
{
public:
  void foo();
};

Invece, in c # scrivi un test come questo:

[TestClass]
public class MyClassTests
{
    [TestMethod]
    public void MyClass_should_have_method_Foo()
    {
        //Arrange
        var myClass = new MyClass();
        //Act
        myClass.Foo();
        //Verify
        Assert.Inconclusive("TODO: Write a more detailed test");
    }
}

Questo test molto semplice trasmette le stesse informazioni del file di intestazione. (Dovremmo avere una classe chiamata "MyClass" con una funzione senza parametri "Foo") Mentre un file di intestazione è più compatto, il test contiene molte più informazioni.

Un avvertimento: un tale processo che prevede che un ingegnere senior fornisca test (in mancanza) per altri sviluppatori per risolvere violentemente conflitti con metodologie come TDD, ma nel tuo caso sarebbe un enorme miglioramento.

    
risposta data 25.01.2018 - 09:50
fonte

Leggi altre domande sui tag