Frage

Ich versuche compareCriteria zu vergleichen. Einfache wie ‚zwischen‘ und ‚InArray‘ oder ‚greaterThan‘. Ich benutze Polymorphismus für diese Klassen. Eine Methode, die sie von der compareCriteria Schnittstelle teilen, ist ‚matchCompareCriteria‘.

Was ich versuche jede Klasse Prüfung für die Art von compareCriteria zu vermeiden haben, sollten sie gegen übereinstimmen. ZB das InArray Objekt prüft, ob matchCompareCriteria ein InArray Objekt übergeben wird, wenn nicht wird es false zurück, in dem Fall, es ist weiß, wie zu vergleichen.

Vielleicht Instanceof vollkommen legitim ist in diesem Fall (die Objekte wissen, über sich selbst), aber immer noch Möglichkeiten, ich bin auf der Suche, es zu vermeiden. Irgendwelche Ideen?

Pseudo-Code-Beispiel:

betweenXandY = create new between class(x, y)
greaterThanZ = create new greaterThan class(z)
greaterThanZ.matchCompareCriteria(betweenXandY)

, wenn X und Y größer als Z wird es wahr zurück.

edit:

1) instanceof ist, was ich sehe, denn jetzt, wie in den matchCompareCriteria Verfahren benötigt. Ich möchte es loswerden

2) matchCompareCritera prüft, ob ein compareCriteria von einem anderen enthalten ist. Wenn alle möglichen Werte von einem von dem anderen enthalten ist, es gibt true zurück. Für viele Kombinationen von compareCriteria doens't es auch Sinn machen, sie zu vergleichen, so dass sie false zurück (wie betweenAlfa und betweenNum wäre unvereinbar sein).

War es hilfreich?

Lösung

Das Problem, das Sie beschreiben, ist Double-Dispatch genannt. Der Name kommt von der Tatsache, dass Sie entscheiden müssen, welches Bit von Code auszuführen (Versand), basierend auf den Typen von zwei Objekten (daher: double).

Normalerweise in OO gibt es Einzelversand - eine Methode für ein Objekt aufrufen verursacht dieses Objekts Durchführung des Verfahrens zur Ausführung

.

In Ihrem Fall haben Sie zwei Objekte, und die Umsetzung ausgeführt wird, hängt von der Art der beiden Objekte. Im Grunde gibt es eine Kopplung durch diese impliziert die „fühlt sich falsch“, wenn Sie bisher nur mit Standard-OO Situationen beschäftigt haben. Aber es ist nicht wirklich falsch -. Es ist nur etwas außerhalb des Problembereiches, was die grundlegenden Funktionen von OO sind zur Lösung direkt geeignet

Wenn Sie eine dynamische Sprache (oder eine statische typisierte Sprache mit Reflexion, die zu diesem Zweck dynamisch genug ist) verwenden Sie diese mit einer Dispatcher-Methode in einer Basisklasse implementieren können. In Pseudo-Code:

class OperatorBase
{
    bool matchCompareCriteria(var other)
    {
        var comparisonMethod = this.GetMethod("matchCompareCriteria" + other.TypeName);
        if (comparisonMethod == null)
            return false;

        return comparisonMethod(other);
    }
}

Hier habe ich mich vor, dass die Sprache eine integrierte Methode in jeder Klasse hat GetMethod genannt, die mir erlaubt, ein Verfahren nach Namen zu suchen, und auch eine Type-Name-Eigenschaft auf jedem Objekt, das mir den Namen des Typs wird von das Objekt. Also, wenn die andere Klasse ein GreaterThan ist, und die abgeleitete Klasse eine Methode namens matchCompareCriteriaGreaterThan hat, nennen wir diese Methode:

class SomeOperator : Base
{
    bool matchCompareCriteriaGreaterThan(var other)
    {
        // 'other' is definitely a GreaterThan, no need to check
    }
}

So Sie nur eine Methode mit dem richtigen Namen schreiben müssen und der Versand erfolgt.

In einer statisch typisierten Sprache, die Methode Überlastung durch Argumenttyp unterstützt, können wir es vermeiden, eine verketteten Namenskonvention zu erfinden - zum Beispiel, hier ist es in C #:

class OperatorBase
{
    public bool CompareWith(object other)
    {
        var compare = GetType().GetMethod("CompareWithType", new[] { other.GetType() });
        if (compare == null)
            return false;

        return (bool)compare.Invoke(this, new[] { other });
    }
}

class GreaterThan : OperatorBase { }
class LessThan : OperatorBase { }

class WithinRange : OperatorBase
{
    // Just write whatever versions of CompareWithType you need.

    public bool CompareWithType(GreaterThan gt)
    {
        return true;
    }

    public bool CompareWithType(LessThan gt)
    {
        return true;
    }
}

class Program
{
    static void Main(string[] args)
    {
        GreaterThan gt = new GreaterThan();
        WithinRange wr = new WithinRange();

        Console.WriteLine(wr.CompareWith(gt));
    }
}

Wenn Sie eine neue Art zu Ihrem Modell hinzufügen, würden Sie bei jedem vorherigen Typ suchen müssen und sich fragen, ob sie brauchen, um mit den neuen Typ in irgendeiner Weise zu interagieren. Folglich alle Art, die eine Art und Weise der Interaktion mit definieren, hat alle anderen Typ - auch wenn die Interaktion einige wirklich einfach ist default (wie „nichts tun, außer Rückkehr true“). Auch die einfache Standard stellt eine bewusste Entscheidung, die Sie treffen müssen. Dies wird durch die Bequemlichkeit verkleidet von nicht mit ausdrücklich für den häufigste Fall keinen Code schreiben zu können.

Daher kann es sinnvoller sein, die Beziehungen zwischen allen Typen in einer externen Tabelle zu erfassen, sondern alle es um die Objekte der Streuung. Der Wert, den es zu zentralisieren wird sein, dass Sie sofort, ob Sie zwischen den Typen, alle wichtigen Wechselwirkungen verpasst haben, sehen können.

So könnte man einen Wörterbuch / map / hashtable hat (was auch immer es in Ihrer Sprache genannt wird), die einen Typen in einem anderen Wörterbuch abbildet. Das zweite Wörterbuch bildet einen zweiten Typ auf der rechten Seite Vergleichsfunktion für diese beiden Typen. Die allgemeine CompareWith Funktion würde diese Datenstruktur verwenden, um die richtige Vergleichsfunktion nachschlagen zu nennen.

Welcher Ansatz richtig ist, hängt davon ab, wie viele Arten Sie wahrscheinlich mit in Ihrem Modell zu beenden.

Andere Tipps

Da Sie instanceof verweisen, ich gehe davon aus arbeiten wir hier in Java. Dies könnte Sie bei Verwendung von Überlastung zu machen. Betrachten wir eine Schnittstelle namens SomeInterface, die eine einzige Methode hat:

public interface SomeInterface {
    public boolean test (SomeInterface s);
}

Nun definieren wir zwei (schlaue Namen) Klassen, die SomeInterface implementieren: Some1 und Some2. Some2 ist langweilig: test immer false zurück. Aber Some1 überschreibt die test Funktion, wenn eine Some2 gegeben:

public class Some1 implements SomeInterface {
    public boolean test (SomeInterface s) {
        return false;
    }

    public boolean test (Some2 s) {
        return true;
    }
}

Dies ermöglicht es uns, die Zeile für Zeile von vermeiden, wenn Aussagen Typprüfung zu tun. Aber es gibt eine Einschränkung. Betrachten Sie diesen Code ein:

Some1 s1 = new Some1 ();
Some2 s2 = new Some2 ();
SomeInterface inter = new Some2 ();

System.out.println(s1.test(s2));     // true
System.out.println(s2.test(s1));     // false
System.out.println(s1.test(inter));  // false

diesen dritten Test sehen? Obwohl inter vom Typ Some2 ist, wird es als SomeInterface stattdessen behandelt. Überladungsauflösung wird zur Compile-Zeit in Java bestimmt, die es für Sie völlig unbrauchbar machen könnten.

Das bringt Sie zurück auf Platz eins: mit instanceof (die zur Laufzeit ausgewertet wird). Auch wenn Sie es auf diese Weise zu tun, es ist immer noch ein schlechtes Design. Jede der Klassen hat über all die anderen wissen. Sollten Sie sich entscheiden eine weitere hinzuzufügen, müssen Sie für alle bestehenden zurück in Funktionalität hinzufügen, um die neue Klasse zu behandeln. Dies wird schrecklich wartbaren in Eile, was ein gutes Zeichen ist, dass das Design ist schlecht.

Ein Redesign ist in Ordnung, aber ohne viel mehr Informationen, kann ich Ihnen keine particluarly gut Schubs in die richtige Richtung geben.

Sie benötigen eine Super-Klasse oder Schnittstelle Kriterien erstellen aufgerufen. Dann wird jede konkrete Unterklasse die Kriterien Schnittstelle implementieren. zwischen, greaterthan etc sind Kriterien ein.

Die Kriterien Klasse wird die matchCompareCriteria Methode angeben, die eine Kriterien akzeptiert. Die eigentliche Logik wird in den Unterklassen befinden.

Sie suchen entweder die Strategie Design-Muster oder dem Template Design-Muster.

Wenn ich gut verstehen, Ihre Methode beruht auf der Typprüfung. Das ist sehr schwer zu vermeiden, und Polymorphismus nicht bei der Lösung des Problems. Von Ihrem Beispiel muss InArray , um den Typ des Parameters zu überprüfen, weil das Verhalten der Methode abhängig zu diesem Thema. Sie können tun, dass nicht durch Polymorphismus, was bedeutet, Sie nicht eine polymorphe Methode auf Klassen, diesen Fall zu behandeln setzen können. Das ist, weil Ihr matchCompareCriteria hängt von der type des Parameters anstatt auf seine Verhalten .

Die Regel nicht instanceof Verwendung gilt, wenn Sie den Typ eines Objekts überprüfen, um zu wählen, welches Verhalten zu haben. Offensichtlich gehört das Verhalten auf die verschiedenen Objekte, deren Typ Sie überprüfen. Aber in diesem Fall ist das Verhalten von Ihrem Objekt hängt von der Art des Objekts, das Sie übergeben werden, in und gehören auf dem anrufenden Objekt, nicht auf den Berufenen wie zuvor. Der Fall ist ähnlich, wenn Sie equals() außer Kraft setzen. Sie haben eine Typprüfung, so dass das Objekt übergeben in der gleichen Art wie this Objekt ist und dann Verhalten implementieren: Wenn der Test fehlschlägt, return false; andernfalls tun, um die Gleichheit Tests.

. Fazit: instanceof verwendet, ist in diesem Fall ok

Hier ist ein längerer Artikel von Steve Yegge, die besser erklärt, ich denke, ein einfaches und unkompliziertes Beispiel. Ich denke, das für Ihr Problem große abbildet.

Denken Sie daran: Polymorphismus ist gut, es sei denn, es ist nicht . :)

Der Smalltalk Ansatz wäre, mehrere Schichten der Hierarchie einzuführen. So zwischen und greaterThan wäre Subklassen von rangedCompareCriteria (oder etwas), und rangeCompareCriteria :: matchCompareCriteria zurückkehren würde < strong> true , wenn Sie gefragt, ob zwei Instanzen von sich selbst vergleichbar waren.

Apropos, möchten Sie wahrscheinlich „matchCompareCriteria“, um etwas zu benennen, die die Absicht etwas besser zum Ausdruck bringt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top