Сведения о вопросе

Getthesound

02:43, 23rd August, 2020

Теги

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

Просмотров: 742   Ответов: 25

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

1. needle.find(haystack)

2. haystack.find(needle)

3. searcher.find(needle, haystack)

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

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

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



  Сведения об ответе

dumai

04:10, 16th August, 2020

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

Принцип единой ответственности заставляет меня не ставить поисковые возможности на мои DTOs или модели. Их обязанность - быть данными, а не находить самих себя, и иголки не должны знать о стогах сена, а стога сена не должны знать об иголках.

Как бы то ни было, я думаю, что большинству практикующих OO требуется LONG времени, чтобы понять, почему #3 является лучшим выбором. Я делал OO в течение десяти лет, вероятно, прежде чем я действительно грокнул его.

@wilhelmtell, C++ - это один из очень немногих языков с шаблонной специализацией, которые делают такую систему реально работающей. Для большинства языков общим назначением метода "find" будет идея HORRIBLE.


  Сведения об ответе

nYU

11:36, 17th August, 2020

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

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

haystack.find(needle, searcher)

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


  Сведения об ответе

SEEYOU

21:36, 26th August, 2020

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

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

Я думаю, что это отличный пример того, как C++ кричит от "in your face!" до OOP. Идея заключается в том, что OOP-это не серебряная пуля какого-либо рода; иногда вещи лучше всего описываются в терминах действий, иногда в терминах объектов, иногда ни то, ни другое, а иногда и то, и другое.

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

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

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

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


  Сведения об ответе

PHPH

01:00, 26th August, 2020

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

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

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

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


  Сведения об ответе

baggs

04:01, 6th August, 2020

В этом вопросе я согласен с Брэдом. Чем больше я работаю над чрезвычайно сложными системами, тем больше я вижу необходимость действительно разделять объекты. Он совершенно прав. Очевидно, что иголка ничего не должна знать о стоге сена, так что 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

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


  Сведения об ответе

PIRLO

15:40, 7th August, 2020

Если и иголка, и стог сена имеют значение DAOs, то варианты 1 и 2 исключаются.

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

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

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

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


  Сведения об ответе

PROGA

04:33, 7th August, 2020

Это всецело зависит от того, что меняется, а что остается неизменным.

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

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


  Сведения об ответе

LAST

15:54, 21st August, 2020

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

  1. needle.find(haystack)

  2. haystack.find(needle)

  3. searcher.find(неедл, стог сена)

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

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

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


  Сведения об ответе

repe

09:31, 28th August, 2020

Чтобы процитировать великих авторов 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

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


  Сведения об ответе

pumpa

02:55, 26th August, 2020

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

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

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


  Сведения об ответе

piter

19:31, 21st August, 2020

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

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

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

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


  Сведения об ответе

dump

01:42, 29th August, 2020

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

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

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


  Сведения об ответе

padenie

17:26, 20th August, 2020

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

  • Космос
  • Солома
  • Игла
  • Самонаводящийся снаряд

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

Иголка, Соломинка
расположены в пространстве
реагируйте на силы

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

Thus   seeker.find(needle, space)   or   seeker.find(needle, space, strategy)

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

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

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

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

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

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

  • прикрепите бирки RFID к вашим иглам, поэтому вы можете легко триангулировать их

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

Так что решайте в соответствии с вашим доменом:

  • Разве стог сена предназначен для того, чтобы содержать иголки? Затем перейдите к решению 2.
  • Разве это естественно, что игла теряется где попало? Затем перейдите к решению 1.
  • Может быть, иголка случайно потерялась в стоге сена? Затем перейдите к решению 3. (или рассмотрим другую стратегию восстановления)


  Сведения об ответе

davran

17:30, 6th August, 2020

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

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

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

Если у вас есть haystack.find(needle, searcher), вы говорите: "выбор наилучшей стратегии поиска лучше всего делать вне контекста стога сена."Я не думаю, что это скорее всего будут исправлять. Я думаю, что более вероятно, что "haystacks know how best to search themselves." добавляет setter, и вы все еще можете вручную ввести поисковик, если вам нужно переопределить или для тестирования.


  Сведения об ответе

FAriza

06:54, 25th August, 2020

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

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


  Сведения об ответе

lool

14:02, 21st August, 2020

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

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


  Сведения об ответе

dump

17:58, 5th August, 2020

@Peter Мейер

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

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


  Сведения об ответе

lool

08:55, 29th August, 2020

У вас также есть четвертая альтернатива, которая, я думаю, будет лучше, чем альтернатива 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) лучше из-за его простоты, поэтому я готов пожертвовать некоторым "correctness" для него.


  Сведения об ответе

park

13:06, 27th August, 2020

haystack.magnet().filter(needle);


  Сведения об ответе

padenie

07:06, 26th August, 2020

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

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


  Сведения об ответе

baggs

21:06, 1st October, 2020

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


  Сведения об ответе

dump

13:06, 26th August, 2020

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

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

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

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

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


  Сведения об ответе

pumpa

05:50, 13th August, 2020

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

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

needle = haystack.findNeedle()

или

needle = searcher.findNeedle(haystack)

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


  Сведения об ответе

darknet

05:21, 8th August, 2020

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

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

Стог сена = IList<IStuff> Игла : IStuff

Искатель .Найти(IStuff stuffToLookFor, IList<IStuff> stuffsToLookIn)

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

так что если вы хотите найти рыбу в океане, вы можете.

var results = Finder.Find(fish, океан)


  Сведения об ответе

ASSembler

01:54, 13th August, 2020

Если у вас есть ссылка на объект иглы, зачем вы его ищете? :) Проблемная область и примеры использования говорят вам, что вам не нужно точное положение иглы в стоге сена (например, что вы могли бы получить от 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);

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться