Wie findet man eine Nadel im Heuhaufen?


74

Wenn Sie eine Nadelsuche eines Heuhaufens objektorientiert durchführen, haben Sie im Wesentlichen drei Alternativen:

1. needle.find(haystack)

2. haystack.find(needle)

3. searcher.find(needle, haystack)

Was bevorzugen Sie und warum?

Ich weiß, dass einige Leute die zweite Alternative bevorzugen, weil sie die Einführung eines dritten Objekts vermeidet. Ich kann jedoch nicht anders, als das Gefühl zu haben, dass der dritte Ansatz konzeptionell "korrekter" ist, zumindest wenn Ihr Ziel darin besteht, "die reale Welt" zu modellieren.

In welchen Fällen halten Sie es für gerechtfertigt, Hilfsobjekte wie den Sucher in diesem Beispiel einzuführen, und wann sollten sie vermieden werden?


1
+1 Guter Titel und gute Semantikfrage. Fast jede OO-Sprache stößt auf ein solches Problem (denken Sie an Pythons string.joinMethode).
new123456

Antworten:


53

Normalerweise sollten Aktionen auf das angewendet werden, worauf Sie die Aktion ausführen ... in diesem Fall auf den Heuhaufen, daher halte ich Option 2 für am besten geeignet.

Sie haben auch eine vierte Alternative, die meiner Meinung nach besser wäre als Alternative 3:

haystack.find(needle, searcher)

In diesem Fall können Sie die Art und Weise angeben, in der Sie als Teil der Aktion suchen möchten, und so die Aktion mit dem Objekt beibehalten, an dem gearbeitet wird.


1
Dies sieht dem Strategiemuster ( en.wikipedia.org/wiki/Strategy_pattern ) sehr ähnlich
ARKBAN

Dies sieht sehr nach einem Verstoß gegen das Prinzip der Einzelverantwortung aus. Option 3 ist definitiv eine bessere Wahl für das Design.
Kyle W. Cartmell

1
Eigentlich ähnelt dies eher dem Besuchermuster; sicherlich ist das seine implizite Absicht. "Sucher" kann jeder Suchalgorithmus sein, der ein Ziel des Besuchers ist. Sicherlich muss etwas von "Haystack" freigelegt werden (die HayCollection, nehme ich an), damit "searcher" suchen kann; Dies bedeutet jedoch nicht, dass SRP tatsächlich oder im Geiste verletzt wird. en.wikipedia.org/wiki/Visitor_pattern .
Radarbob

55

Von den dreien bevorzuge ich Option 3.

Nach dem Prinzip der Einzelverantwortung möchte ich meinen DTOs oder Modellen keine Suchfunktionen hinzufügen. Ihre Verantwortung ist es, Daten zu sein, sich nicht selbst zu finden, noch sollten Nadeln etwas über Heuhaufen wissen müssen, noch sollten Heuhaufen etwas über Nadeln wissen.

Für das, was es wert ist, denke ich, dass die meisten OO-Praktizierenden eine LANGE Zeit brauchen, um zu verstehen, warum # 3 die beste Wahl ist. Ich habe OO wahrscheinlich ein Jahrzehnt lang gemacht, bevor ich es wirklich geschafft habe.

@wilhelmtell, C ++ ist eine der wenigen Sprachen mit Vorlagenspezialisierung, mit denen ein solches System tatsächlich funktioniert. Für die meisten Sprachen wäre eine allgemeine "Find" -Methode eine SCHRECKLICHE Idee.


16

Es gibt eine andere Alternative, nämlich den von der STL von C ++ verwendeten Ansatz:

find(haystack.begin(), haystack.end(), needle)

Ich denke, es ist ein großartiges Beispiel dafür, wie C ++ "in dein Gesicht!" zu OOP. Die Idee ist, dass OOP keine Silberkugel jeglicher Art ist; Manchmal lassen sich Dinge am besten mit Handlungen beschreiben, manchmal mit Objekten, manchmal mit beiden und manchmal mit beiden.

Bjarne Stroustrup sagte in TC ++ PL, dass Sie beim Entwerfen eines Systems bestrebt sein sollten, die Realität unter den Bedingungen eines effektiven und effizienten Codes widerzuspiegeln. Für mich bedeutet dies, dass Sie niemals blindlings etwas folgen sollten. Denken Sie an die Dinge (Heuhaufen, Nadel) und den Kontext, in dem wir uns befinden (suchen, darum geht es in dem Ausdruck).

Wenn der Schwerpunkt auf der Suche liegt, verwenden Sie einen Algorithmus (Aktion), der die Suche hervorhebt (dh flexibel für Heuhaufen, Ozeane, Wüsten, verknüpfte Listen). Wenn der Schwerpunkt auf dem Heuhaufen liegt, kapseln Sie die Suchmethode in das Heuhaufenobjekt und so weiter.

Das heißt, manchmal sind Sie im Zweifel und haben es schwer, eine Wahl zu treffen. In diesem Fall objektorientiert sein. Wenn Sie später Ihre Meinung ändern, ist es meiner Meinung nach einfacher, eine Aktion aus einem Objekt zu extrahieren, als eine Aktion in Objekte und Klassen aufzuteilen.

Befolgen Sie diese Richtlinien, und Ihr Code wird klarer und schöner.


15

Ich würde sagen, dass Option 1 komplett aus ist. Der Code sollte so gelesen werden, dass er Ihnen sagt, was er tut. Option 1 lässt mich denken, dass diese Nadel mir einen Heuhaufen suchen wird.

Option 2 sieht gut aus, wenn ein Heuhaufen Nadeln enthalten soll. ListCollections enthalten immer ListItems, daher ist collection.find (item) natürlich und ausdrucksstark.

Ich denke, die Einführung eines Hilfsobjekts ist angemessen, wenn:

  1. Sie steuern nicht die Implementierung der fraglichen Objekte
    IE: search.find (ObsecureOSObject, Datei)
  2. Es gibt keine regelmäßige oder sinnvolle Beziehung zwischen den Objekten
    IE: nameMatcher.find (Häuser, Bäume.name)

Sie könnten Nadel.FindIn (Heuhaufen) verwenden. Der Variablenname ist hier nicht das Problem, sondern die Syntax.
September 2008

11

Ich bin mit Brad in diesem Fall. Je mehr ich an immens komplexen Systemen arbeite, desto mehr sehe ich die Notwendigkeit, Objekte wirklich zu entkoppeln. Er hat recht. Es ist offensichtlich, dass eine Nadel nichts über Heuhaufen wissen sollte, also ist ich definitiv raus. Ein Heuhaufen sollte jedoch nichts über eine Nadel wissen.

Wenn ich einen Heuhaufen modellieren würde, könnte ich ihn als Sammlung - aber als Sammlung von Heu oder Stroh - implementieren - nicht als Sammlung von Nadeln! Ich würde jedoch berücksichtigen, dass Sachen im Heuhaufen verloren gehen, aber ich weiß nichts darüber, was genau diese Sachen sind. Ich denke, es ist besser, den Heuhaufen nicht nach Gegenständen an sich suchen zu lassen (wie schlau ist ein Heuhaufen überhaupt). Der richtige Ansatz für mich ist, dass der Heuhaufen eine Sammlung von Dingen präsentiert, die sich darin befinden, aber kein Stroh oder Heu sind oder was auch immer einem Heuhaufen seine Essenz verleiht.

class Haystack : ISearchableThingsOnAFarm {
   ICollection<Hay> myHay;
   ICollection<IStuffSmallEnoughToBeLostInAHaystack> stuffLostInMe;

   public ICollection<Hay> Hay {
      get {
         return myHay;
      }
   }

   public ICollection<IStuffSmallEnoughToBeLostInAHayStack> LostAndFound {
      get {
        return stuffLostInMe;
      }
   }
}

class Needle : IStuffSmallEnoughToBeLostInAHaystack {
}

class Farmer {
  Search(Haystack haystack, 
                 IStuffSmallEnoughToBeLostInAHaystack itemToFind)
}

Es gab tatsächlich mehr, was ich in Schnittstellen tippen und abstrahieren wollte, und dann wurde mir klar, wie verrückt ich wurde. Ich fühlte mich wie in einer CS-Klasse am College ...: P.

Du hast die Idee. Ich denke, es ist eine gute Sache, so locker wie möglich gekoppelt zu sein, aber vielleicht wurde ich ein bisschen mitgerissen! :) :)


6

Wenn sowohl Needle als auch Haystack DAOs sind, kommen die Optionen 1 und 2 nicht in Frage.

Der Grund dafür ist, dass DAOs nur für das Speichern von Eigenschaften der von ihnen modellierten Objekte der realen Welt verantwortlich sein sollten und nur Getter- und Setter-Methoden (oder nur direkten Eigenschaftszugriff) haben sollten. Dies erleichtert das Serialisieren der DAOs in eine Datei oder das Erstellen von Methoden für einen generischen Vergleich / eine generische Kopie, da der Code keine ganze Reihe von "if" -Anweisungen zum Überspringen dieser Hilfsmethoden enthalten würde.

Dies lässt nur Option 3 übrig, die den meisten als korrektes Verhalten zustimmen würde.

Option 3 bietet einige Vorteile, wobei der größte Vorteil das Testen von Einheiten ist. Dies liegt daran, dass sowohl Needle- als auch Haystack-Objekte jetzt leicht verspottet werden können. Wenn jedoch Option 1 oder 2 verwendet würde, müsste der interne Status von Needle oder Haystack geändert werden, bevor eine Suche durchgeführt werden könnte.

Zweitens, da sich der Sucher jetzt in einer separaten Klasse befindet, kann der gesamte Suchcode an einem Ort gespeichert werden, einschließlich des allgemeinen Suchcodes. Wenn der Suchcode in das DAO eingefügt würde, würde der allgemeine Suchcode entweder in einer komplizierten Klassenhierarchie oder ohnehin mit einer Searcher Helper-Klasse gespeichert.


5

Dies hängt ganz davon ab, was variiert und was gleich bleibt.

Zum Beispiel arbeite ich an einem (Nicht-OOP-) Framework, bei dem der Suchalgorithmus je nach Nadeltyp und Heuhaufen unterschiedlich ist. Abgesehen von der Tatsache, dass dies in einer objektorientierten Umgebung einen doppelten Versand erfordern würde, bedeutet dies auch, dass es nicht sinnvoll ist, entweder needle.find(haystack)zu schreiben oder zu schreiben haystack.find(needle).

Auf der anderen Seite kann Ihre Anwendung das Finden gerne an eine der beiden Klassen delegieren oder sich an einen Algorithmus halten. In diesem Fall ist die Entscheidung willkürlich. In diesem Fall würde ich den haystack.find(needle)Weg bevorzugen , da es logischer erscheint, den Befund auf den Heuhaufen anzuwenden.


5

Wenn Sie eine Nadelsuche eines Heuhaufens objektorientiert durchführen, haben Sie im Wesentlichen drei Alternativen:

  1. Nadel.Finden (Heuhaufen)

  2. haystack.find (Nadel)

  3. searcher.find (Nadel, Heuhaufen)

Was bevorzugen Sie und warum?

Korrigieren Sie mich , wenn ich falsch liege, aber in allen drei Beispielen Sie bereits haben einen Verweis auf die Nadel Sie suchen, so ist das nicht ein bisschen wie für Ihre Brille suchen , wenn sie auf der Nase sitzen? : p

Abgesehen davon denke ich, dass es wirklich davon abhängt, was Sie für die Verantwortung des Heuhaufens halten, innerhalb der gegebenen Domäne zu sein. Interessieren wir uns nur dafür, dass es sich um eine Sache handelt, die Nadeln enthält (im Wesentlichen eine Sammlung)? Dann ist haystack.find (NeedlePredicate) in Ordnung. Andernfalls ist farmBoy.find (Prädikat, Heuhaufen) möglicherweise besser geeignet.


needlekann ein Typ sein. Aber die Mehrdeutigkeit lässt vermuten, dass dies eine Henne-Ei-Situation sein könnte.
new123456

4

Um die großen Autoren von SICP zu zitieren :

Programme müssen geschrieben werden, damit Benutzer sie lesen können, und nur im Übrigen, damit Maschinen ausgeführt werden können

Ich bevorzuge es, beide Methoden 1 und 2 zur Hand zu haben. Am Beispiel von Ruby .include?wird es so verwendet

haystack.include? needle
=> returns true if the haystack includes the needle

Manchmal möchte ich es jedoch aus rein lesbaren Gründen umdrehen. Ruby kommt nicht mit einer in?Methode, aber es ist ein Einzeiler, also mache ich das oft:

needle.in? haystack
=> exactly the same as above

Wenn es "wichtiger" ist, den Heuhaufen oder die Suchoperation hervorzuheben, schreibe ich lieber include?. Oft ist Ihnen jedoch weder der Heuhaufen noch die Suche wirklich wichtig, nur dass das Objekt vorhanden ist - in diesem Fall in?vermittelt es meiner Meinung nach besser die Bedeutung des Programms.


3

Das hängt von Ihren Anforderungen ab.

Wenn Sie sich beispielsweise nicht für die Eigenschaften des Suchers interessieren (z. B. Sucherstärke, Sehvermögen usw.), würde ich sagen, dass haystack.find (Nadel) die sauberste Lösung ist.

Wenn Sie sich jedoch für die Eigenschaften des Suchers (oder andere Eigenschaften) interessieren, würde ich entweder dem Heuhaufenkonstruktor oder der Funktion eine ISearcher-Schnittstelle hinzufügen, um dies zu ermöglichen. Dies unterstützt sowohl das objektorientierte Design (ein Heuhaufen hat Nadeln) als auch die Inversion der Kontroll- / Abhängigkeitsinjektion (erleichtert das Testen der Funktion "Finden" in Einheiten).


3

Ich kann mir Situationen vorstellen, in denen eine der beiden ersten Geschmacksrichtungen Sinn macht:

  1. Wenn die Nadel wie beim Knuth-Morris-Pratt-Algorithmus vorverarbeitet werden muss needle.findIn(haystack)(oder pattern.findIn(text)), ist dies sinnvoll, da das Nadelobjekt die Zwischentabellen enthält, die erstellt wurden, damit der Algorithmus effektiv funktioniert

  2. Wenn der Heuhaufen wie in einem Versuch vorverarbeitet werden muss, funktioniert das haystack.find(needle)(oder words.hasAWordWithPrefix(prefix)) besser.

In beiden oben genannten Fällen ist einer der Nadeln oder Heuhaufen die Suche bekannt. Außerdem sind sich beide bewusst. Wenn Sie möchten, dass Nadel und Heuhaufen sich oder die Suche nicht bewusst sind, ist searcher.find(needle, haystack)dies angemessen.


2

Einfach: Verbrenne den Heuhaufen! Danach bleibt nur noch die Nadel übrig. Sie können auch Magnete ausprobieren.

Eine schwierigere Frage: Wie finden Sie eine bestimmte Nadel in einem Nadelpool?

Antwort: Fädeln Sie jeden ein und befestigen Sie das andere Ende jedes Fadenstrangs an einem sortierten Index (dh Zeiger).


2

Die Antwort auf diese Frage sollte tatsächlich von der Domäne abhängen, für die die Lösung implementiert ist.
Wenn Sie zufällig eine physische Suche in einem physischen Heuhaufen simulieren, haben Sie möglicherweise die Klassen

  • Raum
  • Stroh
  • Nadel
  • Sucher

Der Raum
weiß, welche Objekte sich an welchen Koordinaten befinden,
setzt die Naturgesetze um (wandelt Energie um, erkennt Kollisionen usw.)

Nadel , Stroh
befinden sich im Weltraum und
reagieren auf Kräfte

Sucher
interagiert mit dem Raum:
    bewegt die Hand, legt ein Magnetfeld an, verbrennt Heu, legt Röntgenstrahlen an, sucht nach einer Nadel ...

So   seeker.find(needle, space)   oder   seeker.find(needle, space, strategy)

Der Heuhaufen befindet sich zufällig in dem Bereich, in dem Sie nach der Nadel suchen. Wenn Sie den Raum als eine Art virtuelle Maschine abstrahieren (denken Sie an: die Matrix), können Sie das Obige mit Heuhaufen anstelle des Raums erhalten (Lösung 3 / 3b) :

seeker.find(needle, haystack)     oder     seeker.find(needle, haystack, strategy)

Aber die Matrix war die Domäne, die nur durch Heuhaufen ersetzt werden sollte, wenn Ihre Nadel nirgendwo anders sein konnte.

Und andererseits war es nur eine Anologie. Interessanterweise öffnet dies den Geist für völlig neue Richtungen:
1. Warum haben Sie die Nadel überhaupt verloren? Können Sie den Prozess ändern, damit Sie ihn nicht verlieren?
2. Müssen Sie die verlorene Nadel finden oder können Sie einfach eine andere bekommen und die erste vergessen? (Dann wäre es schön, wenn sich die Nadel nach einer Weile auflösen würde.)
3. Wenn Sie Ihre Nadeln regelmäßig verlieren und sie wiederfinden müssen, möchten Sie vielleicht

  • mache Nadeln, die sich selbst finden können, zB fragen sie sich regelmäßig: Bin ich verloren? Wenn die Antwort Ja lautet, senden sie ihre GPS-berechnete Position an jemanden oder beginnen zu piepen oder was auch immer:
    needle.find(space)oder needle.find(haystack)    (Lösung 1)

  • Installieren Sie einen Heuhaufen mit einer Kamera auf jedem Strohhalm. Anschließend können Sie den Heuhaufen-Bienenstock fragen, ob er die Nadel in letzter Zeit gesehen hat:
    haystack.find (Nadel) (Lösung 2)

  • Bringen Sie RFID-Tags an Ihren Nadeln an, damit Sie sie leicht triangulieren können

Das ist alles nur zu sagen , dass in Ihrem Implementierung Sie die Nadel gemacht und die Heuhaufen und die meiste Zeit , die Matrix auf irgendeine Art von Niveau.

Entscheiden Sie sich also entsprechend Ihrer Domain:

  • Ist es der Zweck des Heuhaufens, Nadeln zu enthalten? Dann gehen Sie zu Lösung 2.
  • Ist es natürlich, dass die Nadel irgendwo verloren geht? Dann gehen Sie zu Lösung 1.
  • Geht die Nadel versehentlich im Heuhaufen verloren? Dann gehen Sie zu Lösung 3. (oder erwägen Sie eine andere Wiederherstellungsstrategie)

2

haystack.find (Nadel), aber es sollte ein Suchfeld geben.

Ich weiß, dass die Abhängigkeitsinjektion der letzte Schrei ist, daher wundert es mich nicht, dass @Mike Stones haystack.find (Nadel, Sucher) akzeptiert wurde. Aber ich bin anderer Meinung: Die Wahl des Suchers scheint mir eine Entscheidung für den Heuhaufen zu sein.

Betrachten Sie zwei ISearcher: MagneticSearcher iteriert über das Volumen und bewegt und tritt auf eine Weise, die der Stärke des Magneten entspricht. QuickSortSearcher teilt den Stapel in zwei Teile, bis die Nadel in einem der Unterstapel sichtbar ist. Die richtige Wahl des Suchers kann davon abhängen, wie groß der Heuhaufen ist (zum Beispiel relativ zum Magnetfeld), wie die Nadel in den Heuhaufen gelangt ist (dh ist die Position der Nadel wirklich zufällig oder ist sie vorgespannt?) Usw.

Wenn Sie haystack.find (Nadel, Sucher) haben, sagen Sie: "Die Auswahl der besten Suchstrategie erfolgt am besten außerhalb des Kontextes des Heuhaufens." Ich denke nicht, dass das wahrscheinlich richtig ist. Ich denke, es ist wahrscheinlicher, dass "Heuhaufen wissen, wie man sich am besten selbst sucht". Wenn Sie einen Setter hinzufügen, können Sie den Sucher weiterhin manuell injizieren, wenn Sie ihn überschreiben oder testen müssen.


1

Persönlich mag ich die zweite Methode. Meine Argumentation ist, dass die wichtigsten APIs, mit denen ich gearbeitet habe, diesen Ansatz verwenden, und ich finde, dass dies am sinnvollsten ist.

Wenn Sie eine Liste von Dingen haben (Heuhaufen), würden Sie nach der Nadel suchen (find ()).


1

@ Peter Meyer

Du hast die Idee. Ich denke, es ist eine gute Sache, so locker wie möglich gekoppelt zu sein, aber vielleicht wurde ich ein bisschen mitgerissen! :) :)

Ähm ... ja ... ich denke die IStuffSmallEnoughToBeLostInAHaystackArt ist eine rote Fahne :-)


1

Sie haben auch eine vierte Alternative, die meiner Meinung nach besser wäre als Alternative 3:

haystack.find(needle, searcher)

Ich verstehe Ihren Standpunkt, aber was ist, wenn searchereine Suchoberfläche implementiert wird, mit der andere Objekttypen als Heuhaufen durchsucht und andere Dinge als Nadeln darin gefunden werden können?

Die Schnittstelle könnte auch mit verschiedenen Algorithmen implementiert werden, zum Beispiel:

binary_searcher.find(needle, haystack)
vision_searcher.find(pitchfork, haystack)
brute_force_searcher.find(money, wallet)

Aber wie andere bereits betont haben, denke ich auch, dass dies nur hilfreich ist, wenn Sie tatsächlich mehrere Suchalgorithmen oder mehrere durchsuchbare oder auffindbare Klassen haben. Wenn nicht, stimme ich zu, dass haystack.find(needle)es wegen seiner Einfachheit besser ist, also bin ich bereit, etwas "Korrektheit" dafür zu opfern.


1
class Haystack {//whatever
 };
class Needle {//whatever
 }:
class Searcher {
   virtual void find() = 0;
};

class HaystackSearcher::public Searcher {
public:
   HaystackSearcher(Haystack, object)
   virtual void find();
};

Haystack H;
Needle N;
HaystackSearcher HS(H, N);
HS.find();

1

Eine Mischung aus 2 und 3, wirklich.

Einige Heuhaufen haben keine spezielle Suchstrategie. Ein Beispiel hierfür ist ein Array. Die einzige Möglichkeit, etwas zu finden, besteht darin, am Anfang zu beginnen und jedes Element zu testen, bis Sie das gewünschte gefunden haben.

Für diese Art von Dingen ist wahrscheinlich eine freie Funktion am besten (wie C ++).

Einigen Heuhaufen kann eine spezielle Suchstrategie auferlegt werden. Ein Array kann sortiert werden, sodass Sie beispielsweise die binäre Suche verwenden können. Eine freie Funktion (oder ein Paar freier Funktionen, z. B. sort und binary_search) ist wahrscheinlich die beste Option.

Einige Heuhaufen haben im Rahmen ihrer Implementierung eine integrierte Suchstrategie. Assoziative Container (gehashte oder geordnete Sets und Maps) tun dies zum Beispiel. In diesem Fall ist das Finden wahrscheinlich eine wesentliche Suchmethode, daher sollte es wahrscheinlich eine Methode sein, dh haystack.find (Nadel).


1

Heuhaufen kann Dinge enthalten Eine Art von Sachen ist der Nadelsucher ist etwas, das für die Suche nach Sachen verantwortlich ist. Der Sucher kann einen Stapel von Sachen akzeptieren, da die Quelle, wo man etwas findet. Der Finder kann auch eine Beschreibung der Dinge akzeptieren, die er finden muss

Für eine flexible Lösung würden Sie also vorzugsweise Folgendes tun: IStuff-Schnittstelle

Haystack = IList <IStuff> Nadel: IStuff

Finder .Find (IStuff stuffToLookFor, IList <IStuff> stuffsToLookIn)

In diesem Fall wird Ihre Lösung nicht nur an Nadel und Heuhaufen gebunden, sondern kann für jeden Typ verwendet werden, der die Schnittstelle implementiert

Wenn Sie also einen Fisch im Ozean finden möchten, können Sie dies tun.

var results = Finder.Find (Fisch, Ozean)


1

Wenn Sie einen Verweis auf ein Nadelobjekt haben, warum suchen Sie danach? :) Die Problemdomäne und Anwendungsfälle sagen Ihnen, dass Sie keine genaue Position der Nadel im Heuhaufen benötigen (wie das, was Sie von list.indexOf (Element) erhalten könnten), Sie brauchen nur eine Nadel. Und du hast es noch nicht. Meine Antwort lautet also ungefähr so

Needle needle = (Needle)haystack.searchByName("needle");

oder

Needle needle = (Needle)haystack.searchWithFilter(new Filter(){
    public boolean isWhatYouNeed(Object obj)
    {
        return obj instanceof Needle;
    }
});

oder

Needle needle = (Needle)haystack.searchByPattern(Size.SMALL, 
                                                 Sharpness.SHARP, 
                                                 Material.METAL);

Ich bin damit einverstanden, dass es mehr mögliche Lösungen gibt, die auf unterschiedlichen Suchstrategien basieren, sodass sie den Sucher einführen. Es gab einige Kommentare dazu, deshalb beachte ich es hier nicht. Mein Punkt ist, dass Lösungen oben Anwendungsfälle vergessen - was ist der Punkt, um nach etwas zu suchen, wenn Sie bereits einen Verweis darauf haben? Im natürlichsten Anwendungsfall haben Sie noch keine Nadel, daher verwenden Sie keine variable Nadel.


1

Brad Wilson weist darauf hin, dass Objekte eine einzige Verantwortung haben sollten. Im Extremfall hat ein Objekt eine Verantwortung und keinen Zustand. Dann kann es ... eine Funktion werden.

needle = findNeedleIn(haystack);

Oder Sie könnten es so schreiben:

SynchronizedHaystackSearcherProxyFactory proxyFactory =
    SynchronizedHaystackSearcherProxyFactory.getInstance();
StrategyBasedHaystackSearcher searcher =
    new BasicStrategyBasedHaystackSearcher(
        NeedleSeekingStrategies.getMethodicalInstance());
SynchronizedHaystackSearcherProxy proxy =
    proxyFactory.createSynchronizedHaystackSearcherProxy(searcher);
SearchableHaystackAdapter searchableHaystack =
    new SearchableHaystackAdapter(haystack);
FindableSearchResultObject foundObject = null;
while (!HaystackSearcherUtil.isNeedleObject(foundObject)) {
    try {
        foundObject = proxy.find(searchableHaystack);
    } catch (GruesomeInjuryException exc) {
        returnPitchforkToShed();  // sigh, i hate it when this happens
        HaystackSearcherUtil.cleanUp(hay); // XXX fixme not really thread-safe,
                                           // but we can't just leave this mess
        HaystackSearcherUtil.cleanup(exc.getGruesomeMess()); // bug 510000884
        throw exc; // caller will catch this and get us to a hospital,
                   // if it's not already too late
    }
}
return (Needle) BarnyardObjectProtocolUtil.createSynchronizedFindableSearchResultObjectProxyAdapterUnwrapperForToolInterfaceName(SimpleToolInterfaces.NEEDLE_INTERFACE_NAME).adapt(foundObject.getAdaptable());

Lambda, das ultimative Fassadenmuster
Jason Orendorff

1

Der Heuhaufen sollte nichts über die Nadel wissen, und die Nadel sollte nichts über den Heuhaufen wissen. Der Suchende muss über beides Bescheid wissen, aber ob der Heuhaufen wissen sollte, wie er selbst suchen soll, ist der eigentliche Streitpunkt.

Also würde ich mit einer Mischung aus 2 und 3 gehen; Der Heuhaufen sollte in der Lage sein, jemand anderem zu sagen, wie er durchsucht werden soll, und der Suchende sollte in der Lage sein, diese Informationen zum Durchsuchen des Heuhaufens zu verwenden.



1

Versucht der Code, eine bestimmte Nadel oder nur eine Nadel zu finden? Es klingt wie eine dumme Frage, aber es ändert das Problem.

Bei der Suche nach einer bestimmten Nadel ist der Code in der Frage sinnvoll. Auf der Suche nach einer Nadel wäre es eher so

needle = haystack.findNeedle()

oder

needle = searcher.findNeedle(haystack)

In jedem Fall bevorzuge ich einen Sucher dieser Klasse. Ein Heuhaufen kann nicht suchen. Aus CS-Sicht ist es nur ein Datenspeicher mit viel Mist, den Sie nicht wollen.


Das ist eine gute Frage. Ich gehe davon aus, dass wir die spezifische Nadel finden wollen, dh eine, die Sie im Heuhaufen verloren haben. Wenn Sie nur eine Nadel finden wollten, würde der zuvor vorgeschlagene Magnetansatz auch funktionieren ...;)
Anders Sandvig

0

Auf jeden Fall der dritte, IMHO.

Die Frage nach einer Nadel im Heuhaufen ist ein Beispiel für den Versuch, ein Objekt in einer großen Sammlung anderer Objekte zu finden, was darauf hinweist, dass ein komplexer Suchalgorithmus erforderlich ist (möglicherweise mit Magneten oder (wahrscheinlicher) untergeordneten Prozessen), und dies nicht. Es ist sehr sinnvoll, wenn von einem Heuhaufen erwartet wird, dass er Thread-Management durchführt oder komplexe Suchvorgänge implementiert.

Ein Suchobjekt ist jedoch der Suche gewidmet und es kann erwartet werden, dass es weiß, wie untergeordnete Threads für eine schnelle binäre Suche verwaltet werden, oder dass Eigenschaften des gesuchten Elements verwendet werden, um den Bereich einzugrenzen (dh: ein Magnet zum Auffinden von Eisenelementen). .


0

Eine andere Möglichkeit besteht darin, zwei Schnittstellen für durchsuchbare Objekte, z. B. Heuhaufen, und ToBeSearched-Objekte, z. B. Nadel, zu erstellen. So kann es auf diese Weise gemacht werden

public Interface IToBeSearched
{}

public Interface ISearchable
{

    public void Find(IToBeSearched a);

}

Class Needle Implements IToBeSearched
{}

Class Haystack Implements ISearchable
{

    public void Find(IToBeSearched needle)

   {

   //Here goes the original coding of find function

   }

}

0
haystack.iterator.findFirst(/* pass here a predicate returning
                               true if its argument is a needle that we want */)

iteratorkann eine Schnittstelle zu jeder unveränderlichen Sammlung sein, wobei Sammlungen eine gemeinsame findFirst(fun: T => Boolean)Methode haben, die den Job erledigt. Solange der Heuhaufen unveränderlich ist, müssen keine nützlichen Daten von "außen" versteckt werden. Und natürlich ist es nicht gut, die Implementierung einer benutzerdefinierten, nicht trivialen Sammlung und einige andere Dinge, die es gibt, miteinander zu verknüpfen haystack. Teilen und erobern, okay?


0

In den meisten Fällen bevorzuge ich es, einfache Hilfsoperationen wie diese für das Kernobjekt ausführen zu können, aber je nach Sprache steht dem betreffenden Objekt möglicherweise keine ausreichende oder sinnvolle Methode zur Verfügung.

Selbst in Sprachen wie JavaScript , mit denen Sie integrierte Objekte erweitern / erweitern können, kann dies sowohl praktisch als auch problematisch sein (z. B. wenn eine zukünftige Version der Sprache eine effizientere Methode einführt, die von einer benutzerdefinierten Methode überschrieben wird).

In diesem Artikel werden solche Szenarien gut beschrieben.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.