2012-04-30 21 views
32
int a, b, c; 

Constructor() 
{ 
    a = 5; 
    b = 10; 
    c = 15; 
    //do stuff 
} 
Constructor(int x, int y) 
{ 
    a = x; 
    b = y; 
    c = 15; 
    //do stuff 
} 
Constructor(int x, int y, int z) 
{ 
    a = x; 
    b = y; 
    c = z; 
    //do stuff 
} 

Aby uniknąć powielania „rzeczy” i kilka zadań, starałem się coś takiego:Jak mogę użyć wielu konstruktorów do usunięcia zduplikowanego kodu przy zachowaniu czytelności?

int a, b, c; 

Constructor(): this(5, 10, 15) 
{ 
} 
Constructor(int x, int y): this(x, y, 15) 
{ 
} 
Constructor(int x, int y, int z) 
{ 
    a = x; 
    b = y; 
    c = z; 
    //do stuff 
} 

Działa to na to, co chcę zrobić, ale czasami trzeba użyć trochę długi kod, aby utworzyć nowych obiektów lub zrobić kilka obliczeń:

int a, b, c; 

Constructor(): this(new Something(new AnotherThing(param1, param2, param3), 
    10, 15).CollectionOfStuff.Count, new SomethingElse("some string", "another 
    string").GetValue(), (int)Math.Floor(533/39.384)) 
{ 
} 
Constructor(int x, int y): this(x, y, (int)Math.Floor(533/39.384)) 
{ 
} 
Constructor(int x, int y, int z) 
{ 
    a = x; 
    b = y; 
    c = z; 
    //do stuff 
} 

Ten kod jest prawie taka sama jak poprzednio, tylko te parametry, które są przekazywane nie są bardzo czytelne. Wolałbym coś takiego:

int a, b, c; 

Constructor(): this(x, y, z) //compile error, variables do not exist in context 
{ 
    AnotherThing at = new AnotherThing(param1, param2, param3); 
    Something st = new Something(aThing, 10, 15) 
    SomethingElse ste = new SomethingElse("some string", "another string"); 

    int x = thing.CollectionOfStuff.Count; 
    int y = ste.GetValue(); 
    int z = (int)Math.Floor(533/39.384); 

    //In Java, I think you can call this(x, y, z) at this point. 
    this(x, y, z); //compile error, method name expected 
} 
Constructor(int x, int y): this(x, y, z) //compile error 
{ 
    int z = (int)Math.Floor(533/39.384); 
} 
Constructor(int x, int y, int z) 
{ 
    a = x; 
    b = y; 
    c = z; 
    //do stuff 
} 

Zasadniczo buduję parametry w ciele konstruktora. Następnie próbuję przekazać te parametry do innego konstruktora. Myślę, że pamiętam możliwość użycia słów kluczowych "to" i "super" do wywoływania konstruktorów, gdy znajdują się w ciele innego konstruktora podczas kodowania w Javie. To nie wydaje się możliwe w C#.

Czy można to łatwo zrobić? Czy zrobiłem coś niepoprawnie? Jeśli nie jest to możliwe, czy powinienem trzymać się nieczytelnego kodu?

Chyba zawsze mogłem odciąć zduplikowany kod na inną metodę całkowicie poza konstruktorami. Następnie każdy konstruktor po prostu wykona swoją własność i wywoła kod współdzielony przez innych konstruktorów.

Odpowiedz

35

Jako alternatywę do wywoływania metody inicjalizacji ze wszystkich konstruktorów (co uniemożliwia korzystanie z readonly pól) lub metod fabrycznych (które wprowadzają dodatkowe złożoności, gdy masz pochodzący klasach), można użyć parameter object:

int a, b, c; 

public Constructor() 
    : this(new ConstructorParameters()) 
{ 
} 

public Constructor(int x, int y) 
    : this(new ConstructorParameters(x, y)) 
{ 
} 

public Constructor(int x, int y, int z) 
{ 
    a = x; 
    b = y; 
    c = z; 
    //do stuff 
} 

private Constructor(ConstructorParameters parameters) 
    : this(parameters.X, parameters.Y, parameters.Z) 
{ 
} 

private class ConstructorParameters 
{ 
    public int X; 
    public int Y; 
    public int Z; 

    public ConstructorParameters() 
    { 
     AnotherThing at = new AnotherThing(param1, param2, param3); 
     Something st = new Something(at, 10, 15) 
     SomethingElse ste = new SomethingElse("some string", "another string"); 

     X = st.CollectionOfStuff.Count; 
     Y = ste.GetValue(); 
     Z = (int)Math.Floor(533/39.384); 
    } 

    public ConstructorParameters(int x, int y) 
    { 
     X = x; 
     Y = y; 
     Z = (int)Math.Floor(533/39.384); 
    } 
} 
+0

Myślę, że naprawdę mogę polubić tę trasę lepiej niż metody fabryczne. Nie chciałem modyfikować mojego kodu przy użyciu metod fabrycznych, głównie dlatego, że używam dziedziczenia. Będąc początkującym programistą, ciężko mi było wyobrazić sobie wszystkie zmiany, które będą musiały mieć miejsce. Mam kilka przeciążonych konstruktorów w moich klasach bazowych. Wyprowadzone klasy następnie dodają własne bity do konstruktorów bazowych. W zależności od klasy pochodnej potrzebne są różne obliczenia w celu znalezienia określonych parametrów. Używanie klasy prywatnej do obsługi złożonych parametrów wydaje się być prostszym podejściem. – Cheese

+0

Postanowiłem wybrać inne rozwiązanie.Po przeczytaniu opublikowanego linku zacząłem czytać stronę "Zbyt wiele parametrów" w tej samej witrynie. Czytanie przez to pozwoliło mi uznać, że być może konstruktorzy byli zbyt skomplikowani przez wszystkie parametry, które im przekazałem. Postanowiłem przyciąć większość parametrów z konstruktorów. Ustawienie tych pól zostanie wykonane w innym miejscu kodu. Zamiast "jak mogę to zrobić z konstruktorami?", Myślę, że moim prawdziwym problemem było "czy naprawdę muszę przekazać tak wiele parametrów?". Ponieważ podany link doprowadził mnie do mojej odpowiedzi ... – Cheese

+0

, a odpowiedź, którą wysłałeś, była tą, którą uznałam za najlepsze rozwiązanie mojego pierwotnego pytania, wybieram twoją odpowiedź jako odpowiedź. – Cheese

14

Można zrobić

Constructor() : this(5, 10, 15) 
{ 
} 
Constructor(int x, int y) : this(x, y, 15) 
{ 
} 
Constructor(int x, int y, int z) 
{ 
    int a = x; 
    int b = y; 
    int c = z; 
    //do stuff 
} 

Jednak jeśli trzeba zrobić wymyślnej logiki w zależności od parametrów, chciałbym użyć factory pattern:

public class myclass 
{ 
    private myclass(int x, int y, int z) 
    { 
    int a = x; 
    int b = y; 
    int c = z; 
    //do stuff 
    } 
    public static myclass Create() 
    { 
    AnotherThing at = new AnotherThing(param1, param2, param3); 
    Something st = new Something(aThing, 10, 15) 
    SomethingElse ste = new SomethingElse("some string", "another string"); 

    int x = thing.CollectionOfStuff.Count; 
    int y = ste.GetValue(); 
    int z = (int)Math.Floor(533/39.384); 

    return new myclass(x, y ,z); 
    } 
    public static myclass Create(int x, int y) 
    { 
    if (x = 1) 
     return new myclass(x, y, 2) 
    else 
     return new myclass(x, y, 15); 
    } 
    public static myclass Create(int x, int y, int z) 
    { 
    //so on and so forth 
    return new myclass(x, y, z); 
    } 
} 

Chociaż NIE potrzebę się wzór fabryczny, zdecydowanie sprawia, że ​​logika konstruktora jest czytelna.

+0

Myślę, że to przyzwoite rozwiązanie tego, co próbuję osiągnąć. Mój projekt zawiera kilka klas, które będą używane do tworzenia kolekcji anonimowych obiektów. Myślę, że wzór fabryczny można zastosować do wielu lokalizacji w moim kodzie. – Cheese

+0

Dlaczego w języku C# nie można wywołać funkcji konstruktora w innym konstruktorze? (Jeśli tak) –

+0

@MakanTayebi na pewno, ale czasami nie chcesz budować obiektu, jeśli parametry są nieprawidłowe. Jeśli tak jest, większość czasu lepiej jest użyć wzoru fabrycznego, a następnie wygenerować wyjątek w konstruktorze. –

Powiązane problemy