2009-02-04 12 views
6

Czytam książkę Josha Blocha Efektywna Java i sugeruje użycie wzorca projektowania budowniczego podczas budowania obiektów, które mają dużą liczbę członków. Z tego, co widzę, nie wynika wzór waniliowy, ale wygląda na jego odmianę. Raczej podoba mi się jej wygląd i próbowałem go użyć w aplikacji internetowej C#, którą piszę. Jest to kod napisany w Javie i działa idealnieW jaki sposób pojęcie statyczne w języku Java różni się od 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); 
     } 
    } 
} 

Kiedy kładę to na to, co myślę jest C# równoważne

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); 
     } 
    } 
    } 

Potem dostać ostrzeżenia kompilatora. Większość z nich "nie może zadeklarować członków instancji w klasie statycznej".

Moje pytanie brzmi: po pierwsze, co przeoczyłem? Jeśli coś przeoczyłem, czy mogę to zrobić w sposób zalecany przez Josha Blocha, ale w języku C#, a na koniec, i czy ten ważny jest również ten wątek bezpieczny?

+0

Co "wersja": P masz efektywnej Java? Mam stary i nie obejmuje Buildera. Czytałem, że był to jeden z nowych rozdziałów dodanych po Josh experience @ Google. – OscarRyz

Odpowiedz

3

Myślę, że można osiągnąć prawie taki sam efekt, jeśli stworzysz Builder jako klasę najwyższego poziomu (bo to jest dokładnie to, co jest w Javie) i utworzymy fabryczną metodę otrzymywania budowniczego w celu zachowania prywatnego konstruktora (co z kolei pozwoliłoby na zwrócenie instancji podklas w razie potrzeby).

Chodzi o to, aby umożliwić budowniczemu wykonanie kroków niezbędnych do utworzenia obiektu.

Więc (nie wiedząc wiele o C# można spróbować coś takiego)

// 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. 
} 

Cały sens posiadania Builder jako statycznego wewnętrznej klasie własności jest stworzenie wysokiej sprzężenia między nimi (tak jakby oni gdzie). Dlatego metoda budowania w Builder wywołuje prywatny konstruktor "Property".

Prawdopodobnie w języku C# można użyć alternatywnego artefaktu, aby utworzyć to samo połączenie.

+0

Myślę, że spróbuję w ten sposób. Po pierwsze dlatego, że wciąż mogę mieć pojęcie wymaganych wartości, które należy ustawić za pomocą konstruktora i opcjonalne wartości, które można utworzyć za pomocą wywołań do konstruktora. – uriDium

1

Nie jestem pewien, co Java robi z deklaracją klasy statycznej, ale w języku C# klasa statyczna to taka, która ma tylko członków na poziomie klasy i, z definicji, nie może być zaimplementowana w instancję. To jest jak stara różnica VB między klasą a modułem.

2

W języku Java klasa zagnieżdżona jest domyślnie powiązana z określoną instancją jej klasy zawierającej. Instancja klasy zagnieżdżonej może uzyskać dostęp do zmiennych i metod instancji zawierającej. Jeśli klasa zagnieżdżona ma słowo kluczowe "statyczne", nie jest powiązana z wystąpieniem klasy zewnętrznej. W tym sensie Bloch używa słowa kluczowego "static" w klasie Builder.

"Statyczny" oznacza coś innego po zastosowaniu do zagnieżdżonej klasy w języku C#. Nie wiem, jakiego słowa kluczowego używałbyś w C#, a nawet gdyby było to konieczne. Czy próbowałeś zostawić słowo kluczowe static z definicji klas?

Użycie "statycznych" w definicjach klas Java jest omówione w Item 18 of Effective Java.

+0

Myślę, że jest to standardowa definicja w Javie: klasy zagnieżdżone mogą być statyczne lub niestatyczne. Statyczne klasy zagnieżdżone są tak zwane; niestatyczne klasy zagnieżdżone są nazywane klasami wewnętrznymi. –

+0

Odsyłacz do samouczka języka Java wyjaśniający to: http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html –

+0

Ups, mała czara terminologii istnieje. – DJClayworth

13

public static class w języku Java oznacza, że ​​definiujesz statyczną klasę zagnieżdżoną. Oznacza to, że logicznie jest ona zawarta w innej klasie, ale jej instancje mogą istnieć bez odniesienia do jej klasy zewnętrznej. Niestatyczna klasa zagnieżdżona nazywana jest "klasą wewnętrzną", a jej instancje mogą istnieć jedynie w odniesieniu do instancji klasy zewnętrznej.

W języku C# a static class to taki, który nie może być instancjonowany, a zatem nie może mieć żadnych niestatycznych elementów. W języku Java nie ma bezpośredniego odpowiednika tego języka na poziomie języka, ale można łatwo zapobiec tworzeniu instancji klasy Java, udostępniając tylko prywatny konstruktor.

Krótki Java podsumowanie:

  • wszystkie klasy zdefiniowane wewnątrz innej klasy są „zagnieżdżone klas”
  • zagnieżdżonych klas, które nie są static nazywane są wewnętrzne klas
  • przypadki wewnętrznych klas może istnieć tylko w odniesieniu do instancji klasy zewnętrznej Klasy zagnieżdżone klasy nie mają oddzielnej nazwy zagnieżdżone Klasy są wielobajtowe y niezależne od ich klasy zewnętrznej (z wyjątkiem niektórych uprzywilejowanych dostępu).

Byłbym szczęśliwy, gdyby jakiś guru C# powiedział nam, jak klasy wewnętrzne/zagnieżdżone są obsługiwane w C#/.NET.

+0

Myślę, że miałeś na myśli * zagnieżdżony * zamiast * wewnętrzny * w linii 1. –

+0

Masz rację, cały czas je miksuję. –

+0

"Klasy zagnieżdżone są podzielone na dwie kategorie: statyczne i niestatyczne, zagnieżdżone klasy, które są zadeklarowane jako statyczne, są nazywane po prostu statycznymi klasami zagnieżdżonymi. Niestatyczne klasy zagnieżdżone są nazywane klasami wewnętrznymi." - Z http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html –

0

Nie wiem, dlaczego C# narzeka, ale mogę powiedzieć, że kod jest bezpieczny dla wątków. Jeśli tworzyłeś jednocześnie dwie lub więcej instancji Property, każda w swoich własnych wątkach nie napotkałaby żadnych problemów.

2

saua ma właściwą odpowiedź, ale chciałbym być jasne o swoim przykładzie, w szczególności:

W wersji C#, należy usunąć słowa kluczowego statycznej z wnętrza klasy. Nie oznacza to tego samego co wersja Java, a faktycznie efekt, jaki ma w wersji Java, jest normalne zachowanie dla klas wewnętrznych w języku C#.

+0

Czy istnieje sposób, aby uzyskać efekt niestatycznej klasy wewnętrznej z języka Java w języku C#? Aby każda instancja klasy wewnętrznej miała domyślne odniesienie do jej instancji klasy zewnętrznej? –

+0

Jestem też ciekawy. –

+0

Tak, chciałbym też wiedzieć. –

0

Spróbuję usunąć słowo kluczowe static. Moją drugą myślą było, jak już sugerowali inni, stworzenie klasy budowniczej jako najwyższej klasy.

+0

To jest dokładnie to, co powinieneś zrobić - nie buduj klasy budowniczej najwyższego poziomu. –

+0

@Monkey: jeśli słowo kluczowe static zostanie usunięte, nie będzie sposobu na uzyskanie dostępu do programu budującego bez uprzedniego utworzenia właściwości. :( – OscarRyz

0

Aby odpowiedzieć na kilka komentarzy na temat sposobu uzyskania wewnętrznego zachowania klasy w języku C#, wydaje się, że odwołanie do klasy otaczającej musi zostać przekazane w konstruktorze klasy wewnętrznej (z szybkiego Google - C# może mieć od tego czasu dodano możliwość).

public class Outer 
{ 

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

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

W ten sposób C# jasno określa, co Java niejawnie, w tym wyraźnie wymagające odniesienia do dostępu członków zewnętrznej klasy.

Osobiście nigdy nie lubiłem niejawnego dostępu Java do zewnętrznych członków klas, ponieważ wydaje się, że zbyt łatwo się potknąć i przypadkowo złamać hermetyzację - prawie zawsze tworzę moje wewnętrzne klasy jako statyczne i przekazuję im odniesienie do zewnętrznego klasa.

0

Zakładając, że klasa ma publicznie możliwe do ustawienia właściwości odpowiadające członkom budowniczego, nie potrzebujesz wzorca budowniczego Blocha w języku C#. Można użyć obiektów inicjalizatory:

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}; 

    } 
} 

to nie będzie możliwe, jeśli potrzebujesz więcej enkapsulacji.

+0

Być może będę musiał dodać przeciążone metody dla niektórych pól, aby użyć albo identyfikatora albo rzeczywistej wartości tekstowej, więc właściwości nie sprawdzają się dla mnie dobrze. – uriDium

Powiązane problemy