Alex Rivera | Logout

How do you find a needle in a haystack?

Asked 2008-08-22T23:49:32.697
76

When implementing a needle search of a haystack in an object-oriented way, you essentially have three alternatives:

1. needle.find(haystack)

2. haystack.find(needle)

3. searcher.find(needle, haystack)

Which do you prefer, and why?

I know some people prefer the second alternative because it avoids introducing a third object. However, I can't help feeling that the third approach is more conceptually "correct", at least if your goal is to model "the real world".

In which cases do you think it is justified to introduce helper objects, such as the searcher in this example, and when should they be avoided?

Edit
Report

3 Answers

17

There is another alternative, which is the approach utilized by the STL of C++:

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

I think it's a great example of C++ shouting "in your face!" to OOP. The idea is that OOP is not a silver bullet of any kind; sometimes things are best described in terms of actions, sometimes in terms of objects, sometimes neither and sometimes both.

Bjarne Stroustrup said in TC++PL that when you design a system you should strive to reflect reality under the constraints of effective and efficient code. For me, this means you should never follow anything blindly. Think about the things at hand (haystack, needle) and the context we're in (searching, that's what the expression is about).

If the emphasis is about the searching, then using an algorithm (action) that emphasizes searching (i.e. is flexibly to fit haystacks, oceans, deserts, linked lists). If the emphasis is about the haystack, encapsulate the find method inside the haystack object, and so on.

That said, sometimes you're in doubt and have hard times making a choice. In this case, be object oriented. If you change your mind later, I think it is easier to extract an action from an object then to split an action to objects and classes.

Follow these guidelines, and your code will be clearer and, well, more beautiful.

answered 2008-08-23T01:05:14.213
6

If both Needle and Haystack are DAOs, then options 1 and 2 are out of the question.

The reason for this is that DAOs should only be responsible for holding properties of the real world objects they are modeling, and only have getter and setter methods (or just direct property access). This makes serializing the DAOs to a file, or creating methods for a generic compare / generic copy easier to write, as the code wouldn't contain a whole bunch of "if" statements to skip these helper methods.

This just leaves option 3, which most would agree to be correct behaviour.

Option 3 has a few advantages, with the biggest advantage being unit testing. This is because both Needle and Haystack objects can be easily mocked up now, whereas if option 1 or 2 were used, the internal state of either Needle or Haystack would have to be modified before a search could be performed.

Secondly, with the searcher now in a separate class, all search code can be held in one place, including common search code. Whereas if the search code was put into the DAO, common search code would either be stored in a complicated class hierarchy, or with a Searcher Helper class anyway.

answered 2008-09-08T03:47:16.733
0
haystack.iterator.findFirst(/* pass here a predicate returning
                               true if its argument is a needle that we want */)

iterator can be interface to whatever immutable collection, with collections having common findFirst(fun: T => Boolean) method doing the job. As long as the haystack is immutable, no need to hide any useful data from "outside". And, of course, it's not good to tie together implementation of a custom non-trivial collection and some other stuff that does have haystack. Divide and conquer, okay?

answered 2012-08-13T00:42:37.313

Your Answer