2015-07-20 7 views
8

Ich bin relativ neu in Android-Programmierung (~ 2 Monate) Ist es notwendig, Getter für Dutzende von verschiedenen Variablen zu haben?Java - Best Practice für Getters, Single Getter oder Multiple für verschiedene Variablen?

Zum Beispiel -

//Yes I realise that this isn't 'dozens' 
public float getX() { 
    return position.x; 
} 

public float getY() { 
    return position.y; 
} 

public float getWidth() { 
    return width; 
} 

public float getHeight() { 
    return height; 
} 

public float getRotation() { 
    return rotation; 
} 

Während es notwendig wäre, unterschiedliche Getter und Setter für Schwimmer und Streicher zum Beispiel haben, ist es eine schlechte Praxis, und wenn ja, warum es ist, so etwas wie ein Schalter zu verwenden, Anweisung, um verschiedene Variablen zurückzugeben?

public float returnSomething(String theThing) { 
    switch (theThing) { 
     case "height": 
      return height; 
     case "rotation" : 
      return rotation; 
     case "width": 
      return width; 

     default: 
      return 0; 
    } 
} 

Also, wird der obige Code als schlecht angesehen? Wenn ja, bitte erläutern Sie warum.

Danke für jede Hilfe, das ist nicht wirklich ein Problem, da jeder Weg gut funktioniert, ich sehe einfach nicht, warum Leute Dutzende von Getter und Setter verwenden würden, wenn es keinen guten Grund gibt.

nehme ich die gleiche Frage

+0

Der Standardfall, den Sie im zweiten Beispiel hinzufügen müssen, veranschaulicht die Schwäche der zweiten Methode. Sie geben ein gewisses Maß an Sicherheit auf, indem Sie sich erlauben, eine beliebige Saite zu passieren. Wenn Sie beispielsweise eine Dimension enum mit Werten wie "HEIGHT", "ROTATION", "WIDTH" usw. angeben würden, könnten Sie eine ähnliche Funktionalität wie im zweiten Beispiel erreichen, jedoch mit zusätzlicher Typ-Sicherheit. (Alternativ könnten Sie die @StringDef Annotation verwenden ...) – stkent

+0

Mit einem Getter direkt speichern würde eine 'switch' Anweisung (jedes Mal, wenn Sie einen Wert erhalten möchten, müssen Sie alle Fälle umschalten) – Hacketo

+0

Ich werde nie wechseln weil, wenn ich Integer, Float, Strings und boolesche Variablen habe, muss ich noch 4 verschiedene Funktionen einrichten und alle Fälle angeben + es kann eine Chance geben, dass ich eine falsche Zeichenfolge (String theThing) sende und keine Übereinstimmung gefunden wurde, Zweiter Grund Eclipse und Android Studio generiert Getter und Setter für mich, damit ich mich auf meine Logik konzentrieren kann, nicht auf Getter und Setter –

Antwort

9

Da der Moment, den Sie etwas tun, wie

public float returnSomething(String theThing) { 
    switch (theThing) { 
     case "height": 
      return height; 
     case "rotation" : 
      return rotation; 
     case "width": 
      return width; 

     default: 
      return 0; 
    } 
} 

Ich kann die nächste Frage für Stack Overflow, "Warum ist meine Höhe immer 0? "

Und dann Code schreiben wie

public class GameThingy { 
     //... 

    private void doStuff(GameObject gameObject) { 
     float gravity = 5*gameObject.returnSomething("hieght"); 
     gameObject.setSomething("velocyty", gravity+50); 
    } 
} 

Technisch, sobald Sie einen Tippfehler überall machen, werden Sie Probleme haben, die Ursache des Problems zu finden. Das, und du hast Glück, dass die Felder alle float sind, müssen sie nicht sein.

Bearbeiten: Übrigens ist dies ein typisches Problem bei der Definition des Interessensbereichs in einigen Datenbankabfragen. Wie in, muss das Feld, das Sie suchen, durch eine String angeben.

Ein reales Beispiel ist RealmQuery<T>.

A RealmQuery<T> sieht wie folgt aus:

RealmQuery<User> query = realm.where(User.class); 

// Add query conditions: 
query.equalTo("name", "John"); 

// Execute the query: 
RealmResults<User> result1 = query.findAll(); 

Wo sie die Klasse übernehmen User so etwas wie dieses:

public class User { 
    private String name; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 
} 

Eine interessante Anmerkung ist, dass Realm erstellt einen "Proxy-Unterklasse", wo sie neu definieren die setName und getName Methoden (aka, benötigen Sie Getter/Setter, um einige Systeme arbeiten zu lassen! Sie nehmen an, Sie haben sie!)

Aber was hier wichtig ist, ist, dass Sie den Feldnamen mit "name" angeben müssen.

Später kann jemand einen Tippfehler machen, oder Sie einfach nicht daran denken, die Felder weg von der Oberseite des Kopfes. In diesem speziellen Fall neigen sie dazu, ein Metamodell (etwas, das den Namen der Felder für Sie speichert) zu dem Zweck zu erstellen, dass Sie Strings verwenden müssen, um auf Feldnamen verweisen.

Zum Beispiel in Criteria API, statt

Root<Pet> pet = cq.from(Pet.class); 
cq.select(pet.get("name")); 

Sie haben das Metamodell wie folgt aus:

Root<Pet> pet = cq.from(Pet.class); 
cq.select(pet.get(Pet_.name)); 

So ist es entfällt die Notwendigkeit für String s.

Und ähnlich, was neige ich dazu, mit Realm zu tun, ist, dass ich ein „Metamodell“ erstellen (obwohl Sie jetzt es erzeugt für Sie automatisch mit RealmFieldNamesHelper haben kann):

public class User 
     extends RealmObject { 
    @PrimaryKey 
    private long id; 
    private String name; 

    public static enum Fields { //this is the "metamodel" 
     ID("id"), 
     NAME("name"); 

     private String fieldName; 

     Fields(String fieldName) { 
      this.fieldName = fieldName; 
     } 

     public String getField() { 
      return fieldName; 
     } 

     @Override 
     public String toString() { 
      return getField(); 
     } 
    } 
} 

Und so können Sie die ersetzen Abfrage wie so

RealmResults<User> result2 = realm.where(User.class) 
            .equalTo(User.Fields.NAME.getField(), "John") 
            .or() 
            .equalTo(User.Fields.NAME.getField(), "Peter") 
            .findAll(); 

Aber mit Getter und Setter, haben Sie bereits die Art Sicherheit, und Sie haben bereits die Methoden, die Sie haben, um die Oberseite des Kopfes nicht mehr erinnern aus - und so, Sie haben die Fehler bei der Kompilierungszeit.

So Ihre Frage zu beantworten, ist der Grund, warum es eine schlechte Praxis ist in Java zu Variablen durch string name zu beziehen, weil

1.) Tippfehler passieren kann, und der Fehler tritt nur in Laufzeit kompilieren, keine Zeit

2.) es ist nicht typsicher; Sie haben Glück, dass Sie float s zurück, egal was in diesem Beispiel, aber der Moment kann es ein String sein, müssen Sie Object zurückgeben und es oder public <T> T get(String field) { ... } verwenden und wer auch immer die Methode ruft müssen genau wissen, was sie erhalten - auch Laufzeitfehler anfällig.

+0

Das macht Sinn. Ich nahm an, dass es einen Grund geben würde, da so erfahrene Programmierer es anscheinend tun. –

+0

Ich habe gerade jetzt weitere Daten hinzugefügt, wenn Sie neugierig auf ein reales Beispiel sind. – EpicPandaForce

+0

@EpicPandaForce Ihre Antwort ist gut, aber das nächste Mal verwenden Sie kein solches technisches Beispiel, um einen Punkt zu erklären, den ich nach dem Wort EDIT –

1

Sie nur auf Setter gilt brauchen Getter und Setter für die Variablen zu erklären, die Sie verwenden oder aktualisieren müssen.

Ich denke, es ist nur eine Gewohnheit, Ihr returnSomething wird gut funktionieren, aber es ist einfacher zu nennen und verstehen:

class.getHeight() 

als

class.returnSomething("height") 
2

Erstellen Sie einfach Getter und Setter, wenn Sie sie brauchen.

public float returnSomething(String theThing) { 
    switch (theThing) { 
     case "height": 
      return height; 
     case "rotation" : 
      return rotation; 
     case "width": 
      return width; 

     default: 
      return 0; 
    } 
} 

Wenn Sie versuchen, area = returnSomething("width") * returnSomething("heigth") zu tun Sie und wird immer mit 0 Bereich enden. Beachten Sie den Schreibfehler. Wenn Sie separate Methoden haben, sagt der Compiler dies zur Kompilierzeit.

Außerdem müssen Sie viele Prüfungen durchführen, wenn Sie viele Variablen haben.

3

Getters & Setter geben Ihnen Typ Sicherheit. Verwenden Sie es jedoch nur für Variablen, auf die Sie von außerhalb der Klasse zugreifen (setzen/setzen) müssen.Sie können und sollten es minimieren, indem Sie geeignete Konstruktoren verwenden, was in den meisten Fällen der richtige Weg ist, da es die Klarheit des Codes durch Eliminieren magischer Änderungen im Hintergrund erhöht, was für Multi-Thread-Code ein schwerer Schmerz sein kann Ein großes Problem, sogar bei normalem Code mit schlechter Programmierung.

Nur weil Sie zwanzig private Variablen auf Klassenebene haben, bedeutet das nicht, dass Sie getXXX() & setXXX() für jeden erstellen müssen!

BTW: Die meisten IDEs heutzutage wie Eclipse können sie automatisch für Sie generieren.

2

Ich bin auch kein Freund von Gettern/Setter, aber sie sind wahrscheinlich die beste Lösung hier. Die IDE stellt Code-Generierung für solche Felder zur Verfügung.

Grund: Rock solide, nicht fehleranfällig, einfacher für spätere Änderungen.

Machen Sie nur Getter/Setter, wenn sie wirklich benötigt werden. A public void move(float, float) und andere interessantere Methoden können die Koordinatenberechnung weitgehend innerhalb der Klasse selbst platzieren.

1

Interessantes Thema. Ich fühle, dass es eine dritte Antwort gibt. Es gibt ein Argument, das besagt, dass Getters and Setters are evil, und Sie sollten es vermeiden, sie überhaupt zu verwenden. Weil Sie im Wesentlichen Mitglieder als private deklarieren, aber den öffentlichen Änderungszugriff durch Getter und Setter gewähren.

Lassen Sie uns die beiden vergleichen. Hier ist eine Person-Klasse Getter und Setter

public class Person { 
    private String name; 
    private int age; 

    public String getName() { 
     return this.name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public int getAge() { 
     return this.age; 
    } 

    public void setAge(int name) { 
     this.age = age; 
    } 
} 

diese Klasse verwenden:

Person me = new Person(); 
me.setName("Ian"); 
me.setAge(24); 

System.out.println("Name: " + me.getName()); 
System.out.println("Age: " + me.getAge()); 

Lassen Sie uns nun die gleiche Klasse erstellen, ohne Getter und Setter zu verwenden.

public class Person { 
    public String name; 
    public int age; 
} 

und Zugang wird:

Person me = new Person(); 
me.name = "Ian"; 
me.age = 24; 

System.out.println("Name: " + me.name); 
System.out.println("Age: " + me.age); 

Wie Sie die Getter und Setter-Muster fügt ziemlich viel zusätzliche Eingabe sehen. Es gibt jedoch eine Menge von advantages der Verwendung von Getter und Setter.

Informationen

Procedural Code wird dann Entscheidungen trifft:

Das ganze Argument gegen die Verwendung von Getter und Setter in einer objektorientierten Sprache kann wie folgt zusammengefasst werden. Objektorientierter Code sagt Objekten Dinge zu tun. - Alec Sharp

Als ein einfaches Beispiel, sagen wir, dass wir die Informationen von Person in die Datenbank schreiben möchten. Was einige Entwickler neigen dazu, zu tun ist, einen Datenbank-Schnittstelle zu schaffen, die eine Funktion hat,

void writeToPersons(Person person) 

die Getter und Setter zu schreiben, um die erforderlichen Daten in die Datenbank verwenden.

Nach dem Getter und Setter Nay Sager, Person selbst sollte verantwortlich sein für das Schreiben der Datenbank.

public class Person implements Storable { 

    public void writeToDatabase() { 

    } 
} 

Um Ihre Frage zu beantworten, ich würde lieber Getter und Setter als Ihr zweiten Vorschlag verwenden, da Sie schließlich eine Reihe von Konstanten oder Aufzählungen für jede Eigenschaft hinzufügen. Dies erfordert eine Codewartung an zwei verschiedenen Stellen, wodurch einfach ein weiterer Fehlerpunkt hinzugefügt wird.

1

Ich stimme den vorherigen Antworten zu, aber ich werde ein wenig verallgemeinern. Das Problem mit der returnSomething-Methode besteht darin, dass einige Rechtschreibprüfungen von der Kompilierzeit zur Laufzeit verschoben werden.

Es gibt Zeiten und Orte für sehr flexiblen Code, in denen die meisten Prüfungen zur Laufzeit durchgeführt werden. In diesen Situationen verwende ich kein Java. Die großen Vorteile der Kompilierung von Zeitprüfungen und der Sprachen, die sie unterstützen, ist, dass sie äquivalent zu universell quantifizierten Tests sind: "Für jedes kompilierbare Programm, das keine Reflektion verwendet, ist jede get-Anfrage ein gültiges Attribut. " anstatt "Für alle Testfälle in dieser Testsuite ist jede get-Anfrage ein gültiges Attribut".