Il presente articolo è stato tradotto automaticamente.

Il programmatore al lavoro

Piattaforma .NET multiparadigmatica, Parte 2

Ted Neward

Nel mio articolo precedente ( msdn.microsoft.com/magazine/ff955611 ), il primo di questa serie, ho accennato che i due linguaggi centrali per Microsoft .NET Framework, C# e Visual Basic, sono multiparadigm linguaggi come c ++, i sintattico (nel caso di C#) o concettuale (nel caso di Visual Basic) predecessore. Utilizzando un linguaggio multiparadigmatic può essere confuso e difficile, soprattutto quando gli scopi dei paradigmi diversi non chiari.

Analogia e variabilità

Ma prima è possibile iniziare prendendo isolare paradigmi diversi in queste lingue, una domanda più grande deriva da ricordare: Cosa, precisamente, stiamo che cercando di effettuare durante la progettazione di un sistema software? Dimenticare obiettivi “ Fine risultato ”, modularità, estendibilità, semplicità e tutti jazz che, per qualche istante e lo stato attivo più di “ come ” del linguaggio. Come, esattamente, stiamo che cercando di creare tutti questi obiettivi “ risultato finale ”?

James o. Coplien, da c suo “ Multi-Paradigm struttura per ++ ” (Addison-Wesley Professional, 1998), ha una risposta per noi:

Quando si pensa abstractly, abbiamo sottolineare novità comune durante la soppressione dei dettagli. Un'astrazione di una buona software richiede che abbiamo compreso il problema abbastanza bene in tutti i relativi ampiezza sapere cosa è comune tra gli elementi correlati di interesse e sapere cosa dettagli variano da un elemento a altro. Gli elementi di interesse definite collettivamente una famiglia e famiglie, anziché le singole applicazioni, sono nell'ambito dell'architettura e della progettazione. È possibile utilizzare il modello analogia/variabilità indipendentemente se familiari sono moduli, classi, funzioni, processi o tipi;funziona con qualsiasi paradigma. Analogia e variabilità sono al cuore della maggior parte delle tecniche di progettazione.

Considerare il paradigma oggetto tradizionali per qualche istante. Gli sviluppatori orientati a oggetti, ci stiamo insegnati da subito “ identificare i sostantivi ” nel sistema e cercare le cose che compongono una particolare entità, per trovare tutti gli elementi relativi al corso “ docente ” all'interno del sistema, ad esempio e inserirle in una classe denominata docente. Ma se “ sostantivi ” diversi hanno un comportamento sovrapposto e correlato, quali un “ studente ” con alcuni dati e operazioni sovrapposte con una persona “ ” ma con alcune differenze contrassegnato, quindi ci stiamo insegnati piuttosto a replicare il codice comune, è opportuno elevare l'analogia in una classe base che riguardano i tipi a un altro mediante ereditarietà. In altre parole, analogia è raggruppato all'interno di una classe e variabilità viene acquisita mediante l'estensione da quella classe e introdurre le varianti. La capacità di individuare ed esprimere i punti in comune e il livello di variabilità all’interno di un sistema rappresentano l’elemento essenziale della progettazione.

Commonalities sono spesso difficili da identificare in modo esplicito, non perché abbiamo non riconosciuti, ma perché siano facilmente e in modo intuitivo riconoscibile è difficile individuare le parti. Ad esempio, se si pronuncia, “ Vehicle ” quale immagine estrae nella testa? Se eseguiamo questo esercizio con un gruppo di persone, ognuna avrà un'immagine diversa ancora sarà grande analogia tra tutti. Tuttavia, se si avvia diversi veicoli immaginate di elenco, diversi tipi di variabilities iniziano a emergono e classificare stessi (Speriamo), che è possibile ancora alcuni set di commonalities tra i veicoli.

Positive e negative variabilità

Variabilità può entrare in due forme di base, uno dei quali è facile da riconoscere e altre molto più difficile. Variabilità positivo è quando si verifica la variabilità nel modulo di aggiunta all'analogia base. Si supponga ad esempio di astrazione desiderato è che un messaggio, ad esempio un messaggio SOAP o posta elettronica. Se si decide che un tipo di messaggio con intestazione e corpo e lasciare diversi tipi di messaggi che come analogia, quindi una variabilità positivo su questo è un messaggio che contiene un determinato valore nella relativa intestazione, ad esempio la data e l'ora è stato inviato. Questo è in genere facilmente acquisito nei costrutti di linguaggio, ovvero nel paradigma orientato a oggetti viene ad esempio relativamente semplice per creare una sottoclasse di messaggi aggiunge il supporto per data e ora di invio.

Negativo variabilità, tuttavia, è molto più complicato. Come può essere dedotto, una variabilità negativo rimuove o contraddicono alcuni facet dell'analogia, un messaggio contenente un'intestazione ma nessun corpo (ad esempio un messaggio di riconoscimento utilizzato dall'infrastruttura di messaggistica) è una forma di variabilità negativo. E, come si può immaginare probabilmente già, questa acquisizione in un costrutto di linguaggio è problematico, non in C# o in Visual Basic è una funzionalità che consente di rimuovere un membro dichiarato in una classe base. Il meglio che è possibile eseguire in questo caso viene restituito null o nothing dal membro Body, quale chiaramente riprodurrà problemi con qualsiasi codice che prevede un corpo deve essere presente, ad esempio le routine di verifica eseguito un CRC nel corpo per garantire che è stato trasmesso correttamente.

(È interessante, tipi dello schema XML offrono variabilità negativo nelle relative definizioni di convalida dello schema, qualcosa che non mainstream lingua ancora offerte di programmazione, che è uno dei modi che XML Schema Definition possibile mancata corrispondenza con linguaggi di programmazione. Whether this will become a forthcoming feature in some as-yet-unwritten programming language, and whether it would be a Good Thing To Have, is an interesting discussion best had over beer.)

In many systems, negative variability is often handled using explicit code constructs at the client level—meaning, it’s up to the users of the Message type to do some kind of if/else test to see what kind of Message it is before examining the Body, which renders the work put into the Message family all but irrelevant. Too much negative variability escaping the design is usually the underlying cause of calls from developers to “pitch it all and start over.”

Binding Commonality and Variability

Il momento effettivo che siano impostate analogia e variabilità varia con ogni paradigma e, in generale, il più vicino al runtime che è possibile associare tali decisioni maggiore controllo viene fornita ai clienti e agli utenti sull'evoluzione del sistema e nel suo complesso. Quando si parla di un paradigma particolare o tecnica all'interno di un paradigma, è importante riconoscere in cui questi quattro “ associazione volte ” interviene la variabilità:

  1. Ora di origine. Questo è il momento prima generato dal compilatore di, quando lo sviluppatore (o alcune altre entità) crea i file di origine che alla fine verrà essere alimentata nel compilatore. Codice generative tecniche, quali il motore di modelli T4 e a un livello inferiore il sistema ASP.NET, operano a un'associazione in fase di origine.
  2. Fase di compilazione. Come suggerisce il nome, questa associazione si verifica durante il passaggio del compilatore del codice sorgente per il rendering in bytecode compilato o istruzioni eseguibili della CPU. Numerose decisioni finalizzata, sebbene non tutte, come vedremo.
  3. Tempo di collegamento/caricamento. In fase di che caricamento del programma e viene eseguito un ulteriore punto di variabilità interviene, basata su moduli specifici (assembly, nel caso di. NET;DLL, nel caso di codice nativo di Windows) che vengono caricati. Questo è comunemente detto un'architettura plug - in aggiunta-in-stile o quando viene applicato un livello di scala dell'intero programma.
  4. Fase di esecuzione. Durante l'esecuzione del programma siano presenti alcuni variabilities in base all'input dell'utente e decisione codice creando e potenzialmente diverso eseguita (o anche generato) basata su tali decisioni/input.

In alcuni casi, il processo di progettazione verrà da avviare da questi “ associare volte ” e lavoro con le versioni precedenti di scoprire i costrutti di linguaggio che è in grado di supportare il requisito;ad esempio, un utente desideri avere la possibilità di aggiungere e rimuovere/modifica variabilità in esecuzione ora (in modo che non è necessario tornare indietro tramite un ciclo di compilazione o ricaricare il codice), vale a dire che il paradigma utilizza la finestra di progettazione, deve supportare un'associazione di variabilità del runtime.

Sfida

Nel mio articolo precedente, lasciato lettori con una domanda:

Come un esercizio, è consigliabile: .NET Framework 2.0 ha introdotto i generics (tipi con parametri). Perché? Da una prospettiva di progettazione, quale scopo vengono utilizzati? (E per il record, le risposte di “ IT consenta hanno insiemi type-safe ” mancano il punto, Windows Communication Foundation utilizza generics ampiamente, chiaramente in modi che non sono insiemi type-safe praticamente.)

Ciò richiede un po' ulteriormente di esaminare l'implementazione (parziale) di una classe Point in Figura 1 , che rappresenta una cartesiana X / Y punto, come pixel coordina su uno schermo o un grafico più classico.

Figura 1 implementazione parziale di una classe Point

Public Class Point
  Public Sub New(ByVal XX As Integer, ByVal YY As Integer)
    Me.X = XX
    Me.y = YY
  End Sub

  Public Property X() As Integer
  Public Property y() As Integer

  Public Function Distance(ByVal other As Point) As Double
    Dim XDiff = Me.X - other.X
    Dim YDiff = Me.y - other.y
    Return System.Math.Sqrt((XDiff * XDiff) + (YDiff * YDiff))
  End Function

  Public Overrides Function Equals(ByVal obj As Object) As Boolean
    ' Are these the same type?
If Me.GetType() = obj.GetType() Then
      Dim other As Point = obj
      Return other.X = Me.X And other.y = Me.y
    End If
    Return False
  End Function

  Public Overrides Function ToString() As String
    Return String.Format("({0},{1}", Me.X, Me.y)
  End Function

End Class

In e dello stesso non è tutto ciò che davvero interessante. Il resto dell'implementazione viene lasciato all'immaginazione del lettore, perché non è fondamentale per la discussione.

Si noti che questa implementazione punto ha apportato alcune ipotesi sulla modalità che punti dovrebbero essere utilizzate. Ad esempio, gli elementi X e Y del punto di sono valori integer, che significa che questa classe Point può rappresentare punti frazionari, quali punti di (0.5,0.5). Inizialmente, potrebbe trattarsi di una decisione accettabile, ma inevitabilmente, occuperanno una richiesta di chiedere di essere in grado di rappresentare “ punti frazionari ” (per qualsiasi motivo). A questo punto, lo sviluppatore ha un problema interessante: Come rappresentare questo nuovo requisito?

A partire dalla base, let’s fare cosa “ Signore Oh non farlo ” semplicemente creare una nuova classe Point che utilizza membri a virgola mobile anziché membri integrali e vedere cosa sta (vedere la Figura 2 ;Si noti che PointD breve per “ Point-Double, ” ovvero che utilizza copie). Come è abbastanza chiaro, è una grande quantità di sovrapposizione qui concettuali tra i due tipi di punto. In base alla teoria di variabilità/analogia della progettazione, ciò significa che è necessario acquisire le parti comuni e consentire di variabilità in qualche modo. Orientamento agli oggetti classico avrebbe noi farlo tramite l'ereditarietà, elevare l'analogia in una classe base o interfaccia (Point), quindi che l'implementazione nelle sottoclassi (PointI e PointD, forse).

Figura 2 di Una nuova classe Point con membri a virgola mobile

Public Class PointD
  Public Sub New(ByVal XX As Double, ByVal YY As Double)
    Me.X = XX
    Me.y = YY
  End Sub

  Public Property X() As Double
  Public Property y() As Double

  Public Function Distance(ByVal other As Point) As Double
    Dim XDiff = Me.X - other.X
    Dim YDiff = Me.y - other.y
    Return System.Math.Sqrt((XDiff * XDiff) + (YDiff * YDiff))
  End Function

  Public Overrides Function Equals(ByVal obj As Object) As Boolean
    ' Are these the same type?
If Me.GetType() = obj.GetType() Then
      Dim other As PointD = obj
      Return other.X = Me.X And other.y = Me.y
    End If
    Return False
  End Function

  Public Overrides Function ToString() As String
    Return String.Format("({0},{1}", Me.X, Me.y)
  End Function

End Class

Interessanti problemi emergono dal tentativo, tuttavia. Le proprietà X e Y è necessario innanzitutto un tipo associato li ma la variabilità in problemi di due diverse sottoclassi come coordinate X e Y sono memorizzate e pertanto rappresentate agli utenti. Nella finestra di progettazione può sempre semplicemente optare per la rappresentazione di più grande o più ampio o più completa, in questo caso sarebbe un valore Double, ma questo significa pertanto avere un punto che può avere solo valori integer è persa come opzione e Annulla tutto il lavoro previsto per consentire l'ereditarietà. Inoltre, poiché si sta correlate per ereditarietà ora, le due implementazioni di eredità di punti sono ora apparentemente equivalenti in modo si dovrebbe essere in grado di passare un metodo Distance PointI, che potrebbe non essere auspicabile un PointD. Ed è un PointD di (0.0, 0.0) equivalente (come in Equals) per un PointI di (0,0)? Questi problemi sono da considerare.

Anche se questi problemi sono in qualche modo fisso o reso gestibile, altri problemi emergono. Possibile vogliamo successivamente, di un punto che accetta valori superiori a possono essere contenuti in un valore integer. O valori solo in positivo assoluto (che indica l'origine corrisponde all'angolo inferiore sinistro) sono ritenuti accettabili. Ciascuno di questi requisiti diversi significa devono essere create nuove sottoclassi di Point.

L'esecuzione per un momento, il desiderio originale era di riutilizzare l'analogia dell'implementazione di punti ma consentire la variabilità nel tipo/rappresentazione dei valori che costituiscono il punto. In ideale, a seconda del tipo di grafico che si sta lavorando, è necessario essere in grado di scegliere la rappresentazione nel momento in cui che viene creato il punto e dovrebbe rappresentare stesso come un tipo completamente distinto e diverso, che è esattamente cosa generics.

In questo modo, rappresenta tuttavia un problema: Il compilatore prevede che non hanno necessariamente “ Rep ” tipi “ + ” e “-” operatori definiti, poiché riflette desideriamo inserire qui qualsiasi tipo possibile, interi, lunghi, stringhe, pulsanti, DatabaseConnections o qualsiasi altra proviene da ricordare, e che sia chiaramente un po' troppo variabile. Pertanto, ancora una volta, è necessario esprimere alcuni analogia al tipo che può essere utilizzato in questo caso, sotto forma di un vincolo generico di tipi può essere “ Rep ” (vedere di Figura 3).

Figura 3 di un vincolo sul tipo generico

Public Class GPoint(Of Rep As {IComparable, IConvertible})
  Public Sub New(ByVal XX As Rep, ByVal YY As Rep)
    Me.X = XX
    Me.Y = YY
  End Sub

  Public Property X() As Rep
  Public Property Y() As Rep

  Public Function Distance(ByVal other As GPoint(Of Rep)) As Double
    Dim XDiff = (Me.X.ToDouble(Nothing)) - (other.X.ToDouble(Nothing))
    Dim YDiff = (Me.Y.ToDouble(Nothing)) - (other.Y.ToDouble(Nothing))
    Return System.Math.Sqrt((XDiff * XDiff) + (YDiff * YDiff))
  End Function

  Public Overrides Function Equals(ByVal obj As Object) As Boolean
    ' Are these the same type?
If Me.GetType() = obj.GetType() Then
      Dim other As GPoint(Of Rep) = obj
      Return (other.X.CompareTo(Me.X) = 0) And (other.y.CompareTo(Me.Y) = 0)
    End If
    Return False
  End Function

  Public Overrides Function ToString() As String
    Return String.Format("({0},{1}", Me.X, Me.Y)
  End Function

End Class

In questo caso, vengono imposti due vincoli: uno per garantire che qualsiasi tipo “ Rep ” può essere convertito in valori double (per calcolare la distanza tra i due punti) e l'altro per garantire che possono essere confrontato con i valori Y e X costitutivi per verificare se siano maggiore-più/uguale-a/minore-a un altro.

E ora diventa più chiaro il motivo per cui i generics: supportano “ asse ” diverso di variabilità di progettazione che è notevolmente diverso dall'asse tradizionale basato sull'ereditarietà. Consente la finestra di progettazione eseguire il rendering dell'implementazione di tipi di cui si opera dall'implementazione sia variabilities e commonalities.

Si noti che questa implementazione presuppone la variabilità avviene in fase di compilazione anziché in fase di collegamento/caricamento o di esecuzione, se l'utente desidera oppure è necessario specificare il tipo di X / Y membri del punto in fase di esecuzione, una soluzione diversa è necessaria.

Non inattivi (o fine) ancora!

Se tutti i software di progettazione è un esercizio enorme analogia e variabilità, diventa chiara la necessità di comprendere la struttura multiparadigmatic: Ciascuno dei paradigmi diversi offre diversi modi per ottenere questa analogia/variabilità e combinare i paradigmi crea confusione e conduce a chiamate per una riscrittura completa. Come ottenere confusione quando si tenta di associare costrutti tridimensionali nella nostra head in quattro o cinque dimensioni viene avviato il cervello umano, confusione troppe dimensioni di variabilità nel software.

Negli articoli successivi half-dozen o così potrà essere ricerca in modi diversi che ogni paradigma supportata da C# e Visual Basic, i paradigmi strutturale, orientato ad oggetti, metaprogramming, funzionale e dinamici l'identità di, forniscono funzionalità per acquisire analogia e consente la variabilità. Quando siamo tutti che verranno presi in esame come alcuni di essi possono essere combinati in modo interessante per rendere più roba modulare, estensibile, gestibile e tutti gli altri progetti.

Codifica felice!

Ted Neward * è un'entità con Neward &Associa, un'azienda indipendente specializzato in enterprise .NET Framework e i sistemi di piattaforma Java. Ha scritto più di 100 articoli, è un MVP per C# e INETA relatore e ha creato e coautore di libri di una dozzina, tra cui “ Professional F # 2.0 ” (Wrox 2010). Ha inoltre consulta e mentors regolarmente. Reach him at ted@tedneward.com with questions or consulting requests, and read his blog at blogs.tedneward.com.*

Grazie all'esperto di tecnica seguente per la revisione di questo articolo: Anthony verde