2009-02-04 6 views
6

Sto leggendo il libro di Josh Bloch Java efficace e suggerisce di utilizzare un modello di progettazione del builder quando si creano oggetti con grandi quantità di membri. Da quello che riesco a vedere, non è il motivo di design alla vaniglia, ma sembra la sua variazione. Mi piace piuttosto l'aspetto e stavo cercando di usarlo in un'applicazione web C# che sto scrivendo. Questo è il codice scritto in Java e funziona perfettamenteIn che modo la nozione di statica di Java è diversa da quella di C#?

public class Property { 

    private String title; 
    private String area; 

    private int sleeps = 0; 

    public static void main(String[] args) { 

     Property newProperty = new Property.Builder("Test Property").Area("Test Area").Sleeps(7).build(); 

    } 

    private Property(Builder builder) { 
     this.title = builder.title; 
     this.area = builder.area; 
     this.sleeps =builder.sleeps; 
    } 

    public static class Builder{ 
     private String title; 
     private String area; 

     private int sleeps = 0; 

     public Builder (String title){ 
      this.title = title; 
     } 

     public Builder Area(String area){ 
      this.area = area; 
      return this; 
     } 

     public Builder Sleeps(int sleeps){ 
      this.sleeps = sleeps; 
      return this; 
     } 

     public Property build() { 
      return new Property(this); 
     } 
    } 
} 

Quando ho messo questo in quello che penso è il C# equivalente

public class Property 
    { 
    private String title; 
    private String area; 

    private Property(Builder Builder) 
    { 
     title = Builder.title; 
     area = Builder.area; 
    } 


    public static class Builder 
    { 
     // Required parameters 
     private String title; 
     private String area; 

     // Optional parameters 
     private int sleeps = 0; 

     public Builder(String val) 
     { 
      this.title = val; 
     } 

     public Builder Area(String val) 
     { 
      this.area = val; 
      return this; 
     } 

     public Builder Sleeps(int val) 
     { 
      this.sleeps = val; 
      return this; 
     } 

     public Property build() 
     { 
      return new Property(this); 
     } 
    } 
    } 

poi mi avvisi del compilatore. Molti di questi "non possono dichiarare membri di istanze in una classe statica".

Quindi la mia domanda è in primo luogo cosa mi sono perso? Se mi sono perso qualcosa, posso farlo nel modo in cui Josh Bloch consiglia, ma in C#, e infine, e anche questo importante, è sicuro per i thread?

+0

Che "versione": P hai di Java efficace? Ne ho uno vecchio e non copre Builder. Ho letto che era uno dei nuovi capitoli aggiunti dopo Josh experience @ Google. – OscarRyz

risposta

3

Penso che si possa ottenere lo stesso effetto se si crea Builder come classe di livello superiore (per quello è esattamente ciò che è in Java) e si crea un metodo factory per ricevere il builder in modo da mantenere privato il costruttore (che a sua volta ti consentirebbe di restituire istanze di sottoclassi se necessario).

Il punto è consentire al builder di eseguire i passaggi necessari per creare l'oggetto.

So (senza sapere molto su C# si potrebbe provare qualcosa di simile)

// My naive C# attempt:P 

public class Property 
{ 

    public static void main(String []args) 
    { 
     Property p = Property.buildFrom(new Builder("title").Area("area").Etc()) 
    } 
    public static Property buildFrom(Builder builder) 
    { 
     return new Propert(builder); 
    } 

    private Property (Builder builder) 
    { 
     this.area = builder.area; 
     this.title = builder.title; 
     // etc. 
    } 
} 
public class Builder 
{ 
    public Builder (String t) 
    { 
     this.title = t; 
    } 

    public Builder Area(String area) 
    { 
     this.area = area; 
     return this; 
    } 
    // etc. 
} 

L'intero punto di avere Builder come una classe interna statica della proprietà è quello di creare un alto accoppiamento tra i due (come se loro dove uno). Ecco perché il metodo build in Builder chiama il costruttore privato "Property".

Probabilmente in C# è possibile utilizzare un artefatto alternativo per creare lo stesso accoppiamento.

+0

Penso che proverò in questo modo. Innanzitutto perché posso ancora avere la nozione di valori richiesti che devono essere impostati tramite il costruttore e valori facoltativi che possono essere creati attraverso le chiamate al costruttore. – uriDium

1

Non sono sicuro di cosa stia facendo Java con la dichiarazione di classe statica, ma in C#, una classe statica è una che ha solo membri di classe e, per definizione, non può essere implementata in un'istanza. È come la vecchia differenza VB tra Classe e Modulo.

2

In Java una classe nidificata è associata per default a una particolare istanza della sua classe contenente. Un'istanza della classe nidificata può accedere a variabili e metodi dell'istanza contenente. Se la classe nidificata ha la parola chiave "statica", allora non è associata a un'istanza della classe esterna. In questo senso, Bloch utilizza la parola chiave "statica" nella classe Builder.

"Statico" indica qualcosa di diverso se applicato a una classe nidificata in C#. Non so quale parola chiave useresti in C#, o anche se è necessario. Hai provato a lasciare la parola chiave statica fuori dalle definizioni di classe?

L'utilizzo di "statico" nelle definizioni di classe Java è discusso nell'articolo 18 di Java efficace.

+0

Penso che questa sia la definizione standard in Java: le classi nidificate possono essere statiche o non statiche. Le classi nidificate statiche sono chiamate semplicemente così; le classi nidificate non statiche sono chiamate classi interne. –

+0

Link al tutorial Java che spiega questo: http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html –

+0

Oops, piccola terminologia terminologica lì. – DJClayworth

13

public static class in Java significa che si definisce una classe nidificata statica. Ciò significa che è logicamente contenuto in un'altra classe, ma le sue istanze possono esistere senza un riferimento alla sua classe esterna. Una classe nidificata non statica è chiamata "classe interiore" e le sue istanze possono esistere solo in relazione a un'istanza della classe esterna.

In C# a static class è uno che non può essere istanziato e quindi non può avere membri non statici. Non esiste un livello di linguaggio diretto equivalente a questo costrutto in Java, ma è possibile evitare facilmente l'istanziazione di una classe Java fornendo solo un costruttore privato.

Breve Java Ricapitolando:

  • tutte le classi definite all'interno di un'altra Classe sono "classi annidate" Classi
  • nidificati che non sono static sono chiamati classi interne
  • istanze di classi interne può esistere solo in relazione a un'istanza della classe esterna
  • static Le classi nidificate non hanno un nome separato
  • static Le classi nidificate sono di dimensioni maggiori y indipendente dalla loro classe esterna (eccetto per qualche accesso privilegiato).

Sarei felice se qualche guru del C# ci abbia detto come le classi interne/nidificate sono gestite in C# /. NET.

+0

Penso che intendessi * annidato * invece di * interno * nella riga 1. –

+0

Hai ragione, li mescolo tutto il tempo. –

+0

"Le classi annidate sono divise in due categorie: statiche e non statiche Le classi nidificate dichiarate statiche sono semplicemente chiamate classi nidificate statiche. Le classi nidificate non statiche sono chiamate classi interne." - Da http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html –

0

Non so perché C# si lamenti, ma posso dire che il codice è sicuro per i thread. Se stessimo creando due o più istanze di Property allo stesso tempo, ognuna nei propri thread, non si verrebbero a creare problemi.

2

saua ha la risposta giusta, ma mi piacerebbe essere chiaro circa il vostro esempio in particolare:

Nella versione C#, è necessario rimuovere la parola chiave static dalla classe interna. Non significa la stessa cosa della versione Java, e in effetti l'effetto che ha nella versione Java è il comportamento normale per le classi interne in C#.

+0

C'è un modo per ottenere l'effetto di una classe interna non statica da Java in C#? In modo che ogni istanza della classe interna abbia un riferimento implicito alla sua istanza di classe esterna? –

+0

Anch'io sono curioso. –

+0

Sì, mi piacerebbe saperlo anche io. –

0

Proverò a rimuovere la parola chiave statica. Il mio altro pensiero era, come altri hanno già suggerito, era quello di creare la classe costruttore come una classe di alto livello.

+0

Questo è esattamente ciò che dovresti fare: non rendere il builder una classe di alto livello. –

+0

@SMonkey: se la parola chiave static viene rimossa, non ci sarà un modo per accedere al builder senza prima creare la proprietà. :( – OscarRyz

0

Per rispondere a diversi commenti su come ottenere il comportamento della classe interna di Java in C#, sembrerebbe che il riferimento alla classe di inclusione debba essere passato nel costruttore della classe interna (da un rapido Google - C# potrebbe avere aggiunta la capacità).

public class Outer 
{ 

... 
void SomeMethod() { 
    Inner    workerBee=new Inner(this); 
    } 
... 

    class Inner 
    private Outer outer; 
    { 
    Inner(Outer out) { 
     outer=out; 
     } 
    } 
} 

Così C# fa solo esplicito ciò che Java ha fatto implicitamente, tra cui necessitano in modo esplicito il riferimento per accedere ai membri della classe esterna.

Personalmente, non mi sono mai piaciuti gli accessi impliciti di Java ai membri delle classi esterne, dal momento che sembra troppo facile inciampare e spezzare incidentalmente l'incapsulamento - Quasi sempre creo le mie classi interne come statiche e le passo a un riferimento all'esterno classe.

0

Supponendo che la classe abbia proprietà modificabili pubblicamente corrispondenti ai membri del costruttore, non è necessario il modello di build di Bloch in C#. È possibile utilizzare Inizializzatori Object:

public class Property 
{ 

    public String Title {get; set}; 
    public String Area {get; set}; 
    public int Sleeps {get; set}; 

    public static void main(String[] args) 
    { 

     Property newProperty = new Property {Title="Test Property", Area="Test Area", Sleeps=7}; 

    } 
} 

Questo non sarà possibile se avete bisogno di più di incapsulamento.

+0

Potrei aver bisogno di aggiungere metodi sovraccaricati per alcuni dei campi per usare un id o il valore di testo attuale, in modo che le proprietà non funzionino molto bene per me. – uriDium