it-swarm.com.de

Wie gehe ich mit Methoden vor, die nur eine abgeleitete Klasse von einer gemeinsamen Schnittstelle implementiert?

Ich habe eine Schnittstelle (sagen wir in C++), die von einigen abgeleiteten Klassen implementiert wurde. Nehmen wir an, die Benutzeroberfläche sieht folgendermaßen aus:

class IBase
{
  virtual bool method_1() = 0;
  virtual long method_2(const std::string str) = 0;
  // other methods
  virtual long method_10(int value) = 0;
};

und bis jetzt haben 6 verschiedene abgeleitete Klassen (werden in Zukunft mehr sein) die Schnittstelle implementiert. In vielen Algorithmen in meinem Code habe ich diese Schnittstelle polymorph verwendet. z.B:

// some usage
obj = getObject();
if (obj->method_1())
{
  return obj->method_2("Hello");
}
else
{
  return obj->method_10(12);
}

Im Laufe der Zeit habe ich festgestellt, dass es viele Methoden geben würde, die nur von einer abgeleiteten Klasse implementiert werden. Die Frage ist also, ob es das richtige Design ist, diese Methoden in die Schnittstelle einzufügen, oder sollte ich sie direkt in die abgeleiteten Klassen einfügen? Beachten Sie jedoch Folgendes:

  • Wenn ich sie in die Schnittstelle einfüge, werden sie nur von einer abgeleiteten Klasse implementiert, und für die übrigen abgeleiteten Klassen ist die Implementierung leer.
  • Wenn ich sie in die abgeleiteten Klassen einfüge, sind meine implementierten Algorithmen nicht mehr generisch und ich muss den Typ der abgeleiteten Klasse während meiner Algorithmusimplementierung überprüfen.

Was ist in diesem Fall der richtige Weg?

5
Gupta

Wie gehe ich mit Fällen vor, in denen NUR eine abgeleitete Klasse eine Methode über eine gemeinsame Schnittstelle implementieren muss?

Wenn Sie in dieser Situation enden, haben Sie im Allgemeinen ein Problem mit Ihrem Design und sollten es umgestalten.

In Ihrem aufrufenden Code rufen Sie beispielsweise mehrere Methoden für die Klasse auf und treffen Entscheidungen basierend auf den Ergebnissen dieser Methoden. Das ist wahrscheinlich falsch. Stattdessen sollte die Logik in der Klasse und der Schnittstelle gekapselt sein:

interface IShoppingBasket 
{
    void AddItem(Item item); //only one method
}

class ElectronicsShoppingBasket : IShoppinBasket
{
    public void AddItem(Item item)
    {
        if(item.Type == software) //logic is in the class not the calling code
        {
            this.softwareLicences.Add(item); //private method only in this implementation
        }
        else
        {
            this.physicalGoods.Add(item); //private method only in this implementation
        }
    }
}

Ich mache IsSoftwareLicence () oder AddPhysicalGoods () nicht verfügbar, da sie nur die spezifische Implementierung betreffen. Nicht die generische Schnittstelle.

Auf diese Weise kann ich mehrere abgeleitete Klassen mit unterschiedlichen Funktionen erstellen, die jedoch alle dieselbe Aufgabe ausführen.

Für den Fall, dass bestimmte ShoppingBasket-Implementierungen zusätzliche Informationen benötigen, kann dies häufig als Abhängigkeit vom Warenkorb angesehen werden:

class ElectronicsShoppingBasket : IShoppinBasket
{
    public void ElectronicsShoppingBasket (ICustomerDetailsProvider custDet)
    {
        this.custDet = custDet
    }

    public void AddItem(Item item)
    {
       if(this.custDet.GetAddress().Country == Country.NorthKorea)
       {
            throw new Exception("embargoed country"); 
       }
       .....
    }
}

Hier wird der Konstruktor nicht vererbt oder ist Teil der Schnittstelle, aber wir erzwingen die Anforderung, dass ein CustomerDetailsProvider vorhanden ist, wo immer wir einen ElectronicsShoppingBasket haben

Auch hier muss der aufrufende Code nichts über die Kundeninformationen wissen oder eine Logik haben

class CallingCode
{
     public CallingCode(IShoppingBasket sb) //pass me anything as long as it has AddItem
     {
         this.sb = sb;
     }

     public void AddItem(Item item)
     {
          this.sb.AddItem(item); //if you need any other details that's your problem
     }
}
12
Ewan