5 Stimmen

Umgang mit statischen Feldern, die sich je nach implementierender Klasse unterscheiden

Ich habe dieses Problem immer wieder. Angenommen, ich mache eine Befehlszeilenschnittstelle (Java oder C#, das Problem ist das gleiche ich denke, ich werde C# hier zeigen).

  1. Ich definiere eine Schnittstelle ICommand
  2. Ich erstelle eine abstrakte Basisklasse CommandBase, die ICommand implementiert, um gemeinsamen Code zu enthalten.
  3. Ich erstelle mehrere Implementierungsklassen, die jeweils die Basisklasse (und damit die Schnittstelle) erweitern.

Nehmen wir nun an, die Schnittstelle legt fest, dass alle Befehle die Eigenschaft Name und die Methode Execute implementieren...

Für Name muss jede meiner Instanzklassen einen String zurückgeben, der den Namen des Befehls darstellt. Dieser String ("HELP", "PRINT" usw.) ist statisch für die betreffende Klasse. Was ich gerne tun würde, ist zu definieren:

public abstract static const string Name;

Sie können jedoch (leider) keine statischen Mitglieder in einer Schnittstelle definieren.

Ich kämpfe schon seit Jahren mit diesem Problem (so ziemlich überall, wo ich eine Familie mit ähnlichen Klassen habe) und werde daher meine eigenen 3 möglichen Lösungen unten zur Abstimmung stellen. Da jedoch keine von ihnen ideal ist, hoffe ich, dass jemand eine elegantere Lösung posten wird.


UPDATE:

  1. Ich kann die Formatierung des Codes nicht richtig einstellen (Safari/Mac?). Entschuldigung.

  2. Das von mir verwendete Beispiel ist trivial. Im wirklichen Leben gibt es manchmal Dutzende von implementierenden Klassen und mehrere Felder dieses semistatischen Typs (d.h. statisch für die implementierende Klasse).

  3. Ich vergaß zu erwähnen, dass ich diese Informationen idealerweise statisch abfragen können möchte:

    string name = CommandHelp.Name;

2 der 3 von mir vorgeschlagenen Lösungen erfordern, dass die Klasse instanziiert wird, bevor man diese statischen Informationen herausfinden kann, was unschön ist.

3voto

Thomas Danecker Punkte 4500

Sie können in Erwägung ziehen, Attribute anstelle von Feldern zu verwenden.

[Command("HELP")]
class HelpCommand : ICommand
{
}

3voto

Jeromy Irvine Punkte 11205

Wie Sie bereits erwähnt haben, gibt es keine Möglichkeit, dies auf der Ebene der Schnittstelle zu erzwingen. Da Sie jedoch eine abstrakte Klasse verwenden, ist das, was Sie kann ist, die Eigenschaft in der Basisklasse als abstrakt zu deklarieren, was die ererbende Klasse dazu zwingt, sie zu überschreiben. In C# würde das wie folgt aussehen:

public abstract class MyBaseClass
{
  public abstract string Name { get; protected set; }
}

public class MyClass : MyBaseClass
{
  public override string Name
  {
    get { return "CommandName"; }
    protected set { }
  }
}

(Beachten Sie, dass die geschützte Menge verhindert, dass ein externer Code den Namen ändert).

Das ist vielleicht nicht genau das, wonach Sie suchen, aber es kommt dem, was ich glaube, am nächsten. Per Definition sind statische Felder no variieren; man kann einfach nicht ein Mitglied haben, das sowohl statisch als auch überschreibbar für eine bestimmte Klasse ist.

1voto

Marcio Aguiar Punkte 13577
public interface ICommand {
      String getName();
}

public class RealCommand implements ICommand {
     public String getName() {
           return "name";
     }
}

So einfach ist das. Warum sollte man sich die Mühe machen, ein statisches Feld zu haben?


Obs.: Verwenden Sie kein Feld in einer abstrakten Klasse, das in einer Unterklasse initiiert werden sollte (wie David B. Anregung). Was ist, wenn jemand die abstrakte Klasse erweitert und vergisst, das Feld zu initiieren?

0voto

Ewan Makepeace Punkte 5308

[Lösungsvorschlag 1 von 3]

  1. Definieren Sie eine abstrakte Eigenschaft Name in der Schnittstelle, um alle implementierenden Klassen zu zwingen, die Eigenschaft name zu implementieren.
  2. (in c#) Fügen Sie diese Eigenschaft als abstrakt in der Basisklasse hinzu.
  3. In den Implementierungen wird dies so umgesetzt:

    public string Name 
    {
      get {return COMMAND_NAME;}
    }

    Dabei ist name eine in dieser Klasse definierte Konstante.

    Vorteile:

    • Name selbst als Konstante definiert.
    • Die Schnittstelle schreibt vor, dass die Eigenschaft erstellt wird.

    Benachteiligungen:

    • Doppelarbeit (die ich hasse). Die genau die gleiche Eigenschaft Accessor-Code in jeder meiner Implementierungen eingefügt. Warum kann das nicht in der Basisklasse gehen, um das Durcheinander zu vermeiden?

0voto

Bob Dizzle Punkte 1173

Fügen Sie einfach die Eigenschaft name zur Basisklasse hinzu und übergeben Sie sie an den Konstruktor der Basisklasse, und lassen Sie den Konstuktor der abgeleiteten Klasse seinen Befehlsnamen übergeben

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X