Подтвердить что ты не робот

Как найти иглу в стоге сена?

При реализации поиска иглы стога сена объектно-ориентированным способом вы, по существу, имеете три альтернативы:

1. needle.find(haystack)

2. haystack.find(needle)

3. searcher.find(needle, haystack)

Что вы предпочитаете и почему?

Я знаю, что некоторые люди предпочитают вторую альтернативу, потому что она избегает введения третьего объекта. Однако я не могу не почувствовать, что третий подход более концептуально "правильный", по крайней мере, если ваша цель состоит в моделировании "реального мира".

В каких случаях вы считаете оправданным введение вспомогательных объектов, таких как поисковик в этом примере, и когда их следует избегать?

4b9b3361

Ответ 1

Обычно действия должны применяться к тому, что вы делаете на... в этом случае стоге сена, поэтому я думаю, что вариант 2 является наиболее подходящим.

У вас также есть четвертая альтернатива, которая, я думаю, была бы лучше, чем альтернатива 3:

haystack.find(needle, searcher)

В этом случае он позволяет вам указать способ, которым вы хотите выполнить поиск как часть действия, и таким образом вы можете сохранить действие с объектом, который работает.

Ответ 2

Из трех я предпочитаю вариант № 3.

принцип единой ответственности заставляет меня не хотеть добавлять возможности поиска на мои DTO или модели. Их ответственность заключается в том, чтобы быть данными, а не быть самим собой, а также не нуждаться в том, чтобы иглы знали о стогах сена, а также о сенах о хвоях.

Для чего это стоит, я думаю, что большинство практиков OO ДОЛГОЕ время понять, почему № 3 - лучший выбор. Вероятно, я сделал OO в течение десятилетия, прежде чем я действительно это сделал.

@wilhelmtell, С++ - это один из немногих языков со специализацией шаблонов, которые заставляют такую ​​систему работать. Для большинства языков метод "находки" общего назначения был бы УЖАСНОЙ идеей.

Ответ 3

Существует еще одна альтернатива, которая является подходом, используемым STL для С++:

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

Я думаю, что это отличный пример того, как С++ кричит "на вашем лице!". к ООП. Идея заключается в том, что ООП не является серебряной пулей любого вида; иногда вещи лучше всего описываются с точки зрения действий, иногда с точки зрения объектов, иногда ни то, ни другое.

Bjarne Stroustrup сказал в TС++ PL, что при разработке системы вы должны стремиться отражать реальность под ограничениями эффективного и действенного кода. Для меня это означает, что вы никогда не должны следовать слепо. Подумайте о том, что под рукой (стог сена, игла) и контекст, в котором мы находимся (поиск, что это выражение).

Если акцент делается на поиске, то с использованием алгоритма (действия), который подчеркивает поиск (т.е. гибко подходит для стогов сена, океанов, пустынь, связанных списков). Если акцент делается на стоге сена, инкапсулируйте метод find внутри объекта haystack и т.д.

Тем не менее, иногда вы сомневаетесь и испытываете трудности при выборе. В этом случае быть объектно-ориентированным. Если вы передумаете позже, я думаю, что легче извлечь действие из объекта, чтобы разделить действие на объекты и классы.

Следуйте этим рекомендациям, и ваш код станет более четким и, более красивым.

Ответ 4

Я бы сказал, что вариант 1 полностью отсутствует. Код должен читаться так, чтобы он рассказывал вам, что он делает. Вариант 1 заставляет меня думать, что эта игла пойдет искать мне стог сена.

Вариант 2 выглядит хорошо, если стога сена должна содержать иглы. ListCollections всегда будут содержать ListItems, поэтому collection.find(item) является естественным и выразительным.

Я думаю, что введение вспомогательного объекта выполняется, когда:

  • Вы не контролируете реализацию рассматриваемых объектов
    IE: search.find(ObsecureOSObject, файл)
  • Не существует регулярных или разумных отношений между объектами IE: nameMatcher.find(homes, trees.name)

Ответ 5

Я с Брэдом на этом. Чем больше я работаю над чрезвычайно сложными системами, тем больше я вижу необходимость действительно отделять объекты. Он прав. Очевидно, что игла не должна ничего знать о стоге сена, поэтому 1 определенно вышла. Но стог стога ничего не должен знать об иголке.

Если бы я моделировал стог сена, я мог бы реализовать его как коллекцию, но как коллекцию сена или соломы - не набор иголок! Тем не менее, я бы принял во внимание, что материал заблудился в стоге сена, но я ничего не знаю о том, что именно такое. Я думаю, что лучше не ставить стог сена в поисках предметов в себе (насколько это уловка в любом случае). Правильный подход ко мне заключается в том, чтобы стог сена представлял собой коллекцию вещей, которые в ней, но не солома или сено или что-то, что придавало бы сеной свою сущность.

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)
}

На самом деле я больше собирался вводить и абстрагироваться в интерфейсы, а затем понял, как я с ума схожу. Почувствовал, что я был в классе CS в колледже...: P

Вы получаете идею. Я думаю, что как можно смело сочетаться, это хорошо, но, может быть, я немного увлекся!:)

Ответ 6

Если игла и Haystack являются DAO, тогда варианты 1 и 2 не могут быть и речи.

Причиной этого является то, что DAO должны отвечать только за сохранение свойств объектов реального мира, которые они моделируют, и имеют только методы getter и setter (или просто прямой доступ к свойствам). Это делает сериализацию DAO для файла или создание методов для общей копии сравнения/общей копии, которую легче написать, поскольку код не будет содержать целую кучу операторов "if", чтобы пропустить эти вспомогательные методы.

Это просто исключает вариант 3, и большинство из них согласятся на правильное поведение.

Вариант 3 имеет несколько преимуществ, причем самым большим преимуществом является модульное тестирование. Это связано с тем, что и объекты Иглы, и Haystack можно легко высмеять сейчас, тогда как если бы использовались опции 1 или 2, внутреннее состояние либо Needle, либо Haystack должно было быть изменено до того, как будет выполнен поиск.

Во-вторых, теперь, когда поисковик находится в отдельном классе, весь код поиска может храниться в одном месте, включая общий код поиска. Если код поиска был помещен в DAO, общий поисковый код будет либо храниться в сложной иерархии классов, либо в любом случае с классом помощника Searcher.

Ответ 7

При реализации поиска иглы стог сена в объектно-ориентированном виде, у вас по существу есть три альтернативы:

  • needle.find(стог)

  • haystack.find(игла)

  • searcher.find(игла, стог сена)

Что вы предпочитаете и почему?

Исправьте меня, если я ошибаюсь, но во всех трех примерах у вас уже есть ссылка на иглу, которую вы ищете, так разве это не похоже на поиск очков, когда они сидят на носу?: Р

Отбросьте в сторону, я думаю, что это действительно зависит от того, что вы считаете ответственностью стога сена в пределах данного домена. Мы просто заботимся об этом в смысле того, что это предмет, содержащий иголки (сборник, по существу)? Тогда haystack.find(needlePredicate) в порядке. В противном случае может быть более подходящим метод farmBoy.find(предикат, сена).

Ответ 8

Это полностью зависит от того, что меняется и что остается прежним.

Например, я работаю над структурой (non-OOP), где алгоритм поиска отличается в зависимости от типа иглы и стога сена. Помимо того, что для объектно-ориентированной среды это потребует двойной отправки, это также означает, что не имеет смысла писать либо needle.find(haystack), либо писать haystack.find(needle).

С другой стороны, ваше приложение может с радостью делегировать поиск любому из двух классов или придерживаться одного алгоритма в целом, и в этом случае решение является произвольным. В этом случае я предпочел бы путь haystack.find(needle), потому что кажется более логичным применить обнаружение к стоге сена.

Ответ 9

Это зависит от ваших требований.

Например, если вас не интересуют свойства поисковика (например, сила поиска, видение и т.д.), я бы сказал, что haystack.find(игла) будет самым чистым решением.

Но если вы заботитесь о свойствах поисковика (или каких-либо других свойств, если на то пошло), я бы ввел интерфейс ISearcher в конструктор haystack или функцию, чтобы облегчить это. Это поддерживает как объектно-ориентированный дизайн (стог сена с иглами), так и инверсию инъекции управления/зависимости (облегчает unit test функцию "найти" ).

Ответ 10

Процитировать великих авторов SICP,

Программы должны быть написаны для чтения людьми, и только случайно для машин для выполнения

Я предпочитаю иметь оба метода 1 и 2 под рукой. Используя ruby ​​в качестве примера, он поставляется с .include?, который используется как

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

Иногда, хотя и по соображениям удобочитаемости, я хочу перевернуть его. Ruby не имеет метода in?, но он однострочный, поэтому я часто делаю это:

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

Если "более важно" подчеркнуть стог сена или операцию поиска, я предпочитаю писать include?. Часто, однако, ни стог сена, ни поиск не являются тем, о чем вы заботитесь, только что объект присутствует - в этом случае я нахожу in? лучше передает смысл программы.

Ответ 11

Я могу думать о ситуациях, когда имеет смысл любой из первых двух вариантов:

  • Если игла нуждается в предварительной обработке, как в алгоритме Кнута-Морриса-Пратта, needle.findIn(haystack) (или pattern.findIn(text)) имеет смысл, так как игольчатый объект удерживает промежуточные таблицы, созданные для работы алгоритма эффективно

  • Если стог сена требует предварительной обработки, как говорят в trie, haystack.find(needle) (или words.hasAWordWithPrefix(prefix)) работает лучше.

В обоих случаях один из игл или стог сена знает о поиске. Кроме того, они оба знают друг о друге. Если вы хотите, чтобы игла и стог сена не знали друг о друге или поиска, searcher.find(needle, haystack) был бы уместным.

Ответ 12

Легко: зажгите стог сена! После этого останется только игла. Кроме того, вы можете попробовать магниты.

Более сложный вопрос: как найти одну иглу в пучке игл?

Ответ: поидите каждый из них и присоедините другой конец каждой нити потока к отсортированному индексу (т.е. указателям)

Ответ 13

Ответ на этот вопрос должен фактически зависеть от того, в каком домене реализовано решение.
Если вы случайно моделируете физический поиск в физической стоге сена, вы можете иметь классы

  • Пробел
  • Солома
  • Игла
  • Seeker

Космос
знает, какие объекты находятся, где координаты
реализует законы природы (преобразует энергию, обнаруживает столкновения и т.д.)

Игла, Солома
находятся в космосе реагировать на силы

Seeker
взаимодействует с пространством:
    перемещает руку, применяет магнитное поле, сжигает сено, применяет рентгеновские лучи, ищет иглу...

Таким образом,   seeker.find(needle, space)     seeker.find(needle, space, strategy)

Стопка сена просто оказывается в пространстве, где вы ищете иглу. Когда вы абстрагируете пространство как своего рода виртуальную машину (подумайте: матрица), вы можете получить выше с помощью стога сена вместо пространства (решение 3/3b):

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

Но матрицей был Домен, который должен быть заменен только сторой сена, если ваша игла не могла быть где-либо еще.

И снова это было всего лишь анология. Интересно, что это открывает ум для совершенно новых направлений:
1. Почему вы потеряли иглу в первую очередь? Можете ли вы изменить процесс, чтобы вы не потеряли его?
2. Вам нужно найти потерянную иглу, или вы можете просто получить другую и забыть о первом? (Тогда было бы хорошо, если бы игла растворилась через некоторое время)
3. Если вы регулярно теряете иглы, и вам нужно их снова найти, вы можете захотеть

  • делают иглы, которые могут найти себя, например. они регулярно спрашивают себя: "Я проиграл? Если ответ" да", они отправляют свое GPS-рассчитанное положение кому-то или начинают звуковой сигнал или что-то еще:
    needle.find(space) или needle.find(haystack)   (решение 1)

  • установите стог сена с камерой на каждую соломинку, после чего вы можете попросить улей улья сена, если он увидит иглу в последнее время:
    haystack.find(игла) (решение 2)

  • присоединяйте метки RFID к вашим иглам, чтобы вы могли легко их триангулировать.

Чтобы все просто сказать, что в вашей реализации вы сделали иглу и стог сена и большую часть времени матрицей на каком-то уровне.

Итак, решите в соответствии с вашим доменом:

  • Является ли это целью стога сена содержать иглы? Тогда переходим к решению 2.
  • Естественно ли, что игла теряется где угодно? Тогда переходим к решению 1.
  • Игла теряется в стоге сена случайно? Затем перейдите к решению 3. (или рассмотрите другую стратегию восстановления)

Ответ 14

haystack.find(игла), но должно быть поле поиска.

Я знаю, что инъекция зависимостей - это все ярость, поэтому меня не удивляет, что был принят Xay Stone Stone Haystack.find(игла, искатель). Но я не согласен: выбор того, какой искатель используется, кажется мне решением для стога сена.

Рассмотрим два исследователя: MagneticSearcher выполняет итерацию по объему, перемещая и помещая магнит в соответствии с силой магнита. QuickSortSearcher делит стек на два, пока игла не проявится в одном из подтипов. Правильный выбор искателя может зависеть от того, насколько велика стога сена (например, относительно магнитного поля), как игла попала в стог сена (т.е. Положение иглы действительно случайное или оно смещено?) И т.д.

Если у вас есть haystack.find(игла, искатель), вы говорите: "Выбор из которого - лучшая стратегия поиска, лучше всего сделать за пределами контекста стога сена". Я не думаю, что это будет правильно. Я думаю, что более вероятно, что "стога сена" знают, как лучше искать себя ". Добавьте установщик, и вы можете вручную ввести поискового пользователя, если вам нужно переопределить или проверить.

Ответ 15

Лично мне нравится второй метод. Мое рассуждение связано с тем, что основные API-интерфейсы, с которыми я работал, используют этот подход, и я считаю, что это имеет наибольший смысл.

Если у вас есть список вещей (стога сена), вы будете искать (find()) иглу.

Ответ 16

@Peter Meyer

Вы получаете идею. Я думаю, что как можно смело сочетаться, это хорошо, но, может быть, я немного увлекся!:)

Errr... да... Я думаю, что IStuffSmallEnoughToBeLostInAHaystack - это красный флаг: -)

Ответ 17

У вас также есть четвертая альтернатива, которая, я думаю, была бы лучше, чем альтернатива 3:

haystack.find(needle, searcher)

Я вижу вашу мысль, но что, если searcher реализует интерфейс поиска, который позволяет искать другие типы объектов, чем стога сена, и находить в них другие вещи, кроме игл?

Интерфейс также может быть реализован с использованием разных алгоритмов, например:

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

Но, как уже отмечали другие, я также думаю, что это полезно только в том случае, если у вас на самом деле есть несколько алгоритмов поиска или несколько классов с возможностью поиска или поиска. Если нет, я согласен, что haystack.find(needle) лучше из-за его простоты, поэтому я готов пожертвовать некоторой "правильностью" для него.

Ответ 18

haystack.magnet().filter(needle);

Ответ 19

Стопка сена не должна знать о игле, и игла не должна знать о стоге сена. Поисковик должен знать об обоих, но должен ли стог сена должен знать, как искать себя, является реальной точкой в ​​споре.

Итак, я бы пошел с миксами 2 и 3; стог сена должен быть в состоянии сказать кому-то еще, как искать его, и поисковик должен иметь возможность использовать эту информацию для поиска стога сена.

Ответ 20

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();

Ответ 21

На самом деле смесь 2 и 3.

Некоторые стога сена не имеют специализированной стратегии поиска; примером этого является массив. Единственный способ найти что-то - начать с самого начала и проверить каждый элемент, пока не найдете тот, который вам нужен.

Для такого рода вещей функция, вероятно, лучше всего (например, С++).

Некоторые стога сена могут иметь наложенную на них специализированную стратегию поиска. Массив можно сортировать, что позволяет использовать двоичный поиск, например. Лучшая опция - свободная функция (или пара свободных функций, например sort и binary_search).

Некоторые стога сена имеют интегрированную стратегию поиска как часть их реализации; например, ассоциативные контейнеры (хешированные или упорядоченные наборы и карты). В этом случае поиск, вероятно, является важным методом поиска, поэтому, вероятно, это должен быть метод, то есть haystack.find(игла).

Ответ 22

Является ли код попыткой найти конкретную иглу или любую иглу? Это звучит как глупый вопрос, но он меняет проблему.

В поисках конкретной иглы код в вопросе имеет смысл. В поисках любой иглы это было бы больше похоже на

needle = haystack.findNeedle()

или

needle = searcher.findNeedle(haystack)

В любом случае, я предпочитаю иметь этот класс. Стопка сена не знает, как искать. С точки зрения CS это просто хранилище данных с LOTS дерьмом, которого вы не хотите.

Ответ 23

Сена может содержать вещи одним типом материала является иголка искатель - это то, что отвечает за поиск вещей искатель может принять кучу вещей как источник того, где найти вещь finder может также принять описание материала, которое нужно найти

поэтому, желательно, для гибкого решения вы бы сделали что-то вроде: Интерфейс IStuff

Haystack = IList <IStuff> Игла: IStuff

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

В этом случае ваше решение не будет привязано к иглам и стогам сена, но оно может использоваться для любого типа, реализующего интерфейс

поэтому, если вы хотите найти Рыба в океане, вы можете.

var results = Finder.Find(рыба, океан)

Ответ 24

Если у вас есть ссылка на объект иглы, почему вы его ищете?:) В проблемной области и прецедентах вам сообщается, что вам не нужно точное положение иглы в стоге сена (например, что вы можете получить из list.indexOf(element)), вам просто нужна игла. И у вас его еще нет. Итак, мой ответ - это что-то вроде этого

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

или

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

или

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

Я согласен, что существует более возможные решения, основанные на разных стратегиях поиска, поэтому они вводят поисковика. На это были и комментарии, поэтому я не обращал на это внимания. Моя точка зрения заключается в том, что решения выше забывают о прецедентах - какой смысл искать что-то, если у вас уже есть ссылка на него? В самом естественном случае использования у вас еще нет иглы, поэтому вы не используете переменную иглу.

Ответ 25

Брэд Уилсон указывает, что объекты должны нести единую ответственность. В крайнем случае объект несет одну ответственность и не имеет никакого состояния. Тогда он может стать... функцией.

needle = findNeedleIn(haystack);

Или вы могли бы написать это следующим образом:

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 not already too late
    }
}
return (Needle) BarnyardObjectProtocolUtil.createSynchronizedFindableSearchResultObjectProxyAdapterUnwrapperForToolInterfaceName(SimpleToolInterfaces.NEEDLE_INTERFACE_NAME).adapt(foundObject.getAdaptable());

Ответ 26

Определенно третий, IMHO.

Вопрос об иглах в стоге сена - пример попытки найти один объект в большой коллекции других, что указывает на необходимость сложного алгоритма поиска (возможно, с использованием магнитов или (более вероятных) дочерних процессов) и для столовой сена не имеет смысла делать управление потоками или выполнять сложные поиски.

Объект поиска, однако, предназначен для поиска и может ожидать, что он будет знать, как управлять дочерними потоками для быстрого бинарного поиска, или использовать свойства искомого элемента для сужения области (т.е. магнита, чтобы найти черные изделия).

Ответ 27

Другим возможным способом может быть создание двух интерфейсов для объекта Searchable, например. haystack и ToBeSearched object, например. игла. Таким образом, это можно сделать таким образом.

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

   }

}

Ответ 28

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

iterator может быть интерфейсом для любой неизменяемой коллекции, при этом коллекции, имеющие общий метод findFirst(fun: T => Boolean), выполняют работу. Пока стог сена неизменен, не нужно скрывать какие-либо полезные данные из "снаружи". И, конечно, нехорошо связывать реализацию пользовательской нетривиальной коллекции и некоторых других вещей, которые имеют haystack. Разделите и победите, хорошо?