Нужен ли абстрактный класс или интерфейс здесь (или ни один)? - PullRequest
1 голос
/ 25 марта 2009

У меня есть склад. Иногда я хочу найти местоположение блока по имени, иногда по описанию, иногда по UPC, может быть, что-то еще и т. Д. Каждый из этих методов поиска вызывает одни и те же различные частные методы, чтобы найти информацию, которая поможет найти данные.

Например, upc вызывает закрытый метод для поиска rowid, как и name, так же, как и X. Поэтому мне нужен этот метод для всех них. Я мог бы использовать этот rowid для того, чтобы найти место на полке (это только пример.)

Но у меня вопрос, должен ли я иметь абстрактный класс (или что-то еще), потому что я смотрю в свою коробку разными способами.

Другими словами, скажем, мой код для поиска очень похож на UPC и на местоположение. Каждый метод может вызывать что-то с помощью (выберите * из xxxx, где location =, или выберите * из xxxx, где upc =). Я мог бы просто создать два разных метода в одном классе

LocateByUPC(string upc)...
LocateByLocation(string location)...
LocateByDescription(string description)

... опять же, это было бы в одном большом классе

Была бы какая-то причина, по которой я хотел бы иметь суперкласс, который будет содержать

abstract class MySuper
{

properties...

LocateBox(string mycriteria)...

}

, а затем наследовать это и создать второй класс, который переопределяет метод LocateBox для любой нужной мне версии?

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

Использование C #, если это имеет значение.

Edit - я бы сделал это, если бы дал кому-то .dll без источника, но с определением класса? Класс Def. сказал бы мои свойства и т. д. и какие методы переопределить.

Ответы [ 8 ]

2 голосов
/ 25 марта 2009

Ни

ни использование абстрактного класса, ни интерфейса не упростят протокол, т. Е. У вас все равно останется куча методов LocateXXX

Я бы порекомендовал использовать общий метод Locate (строковые критерии) в качестве основы и определять сигнатуры только для тех методов, которые, как вы знаете, будут часто использоваться; универсальный может быть универсальным для будущего расширения в случае необходимости (а использование универсального упрощает кодирование и тестирование)

1 голос
/ 25 марта 2009

Похоже, вы захотите реализовать шаблон проектирования под названием Template Method. По сути, вы бы определили схему алгоритма поиска в базовом классе как конечные методы, поместив общий код в эти методы. Для методов, которые требуют различного поведения в зависимости от типа, просто сделайте так, чтобы конечные методы базового класса вызывали защищенные методы в дочерних элементах, и чтобы каждый дочерний тип реализовывал это поведение.

Вы можете посмотреть онлайн некоторые ресурсы, просто сделайте в Google поиск по шаблону шаблона проектирования. Надеюсь, это поможет пролить свет на ваш вопрос.

0 голосов
/ 05 мая 2009

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

Итак,

LocateBy (Constraint constraint);

и

abstract class Constraint {
   String toString ();
}

class LocationConstraint extends Constraint { /* ... */}

и т.д.

0 голосов
/ 13 апреля 2009

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

Примером полезного интерфейса является тот, где вы не имели отношения предметы, которые должны обеспечивать аналогичную функциональность в униформе путь. Например, у вас может быть CMS, где статьи хранятся в базы данных, но где система кэширует их на диск, а также HTML страниц, пока статья в базе данных не будет изменена, после чего физический файл удаляется до следующего доступа к скопировать в базу данных. Ваша CMS также может поддерживать возможность пользователи могут загружать изображения, PDF-файлы и т. д. для хранения на диске, но вы определенно не хотите, чтобы эти файлы были удалены как копия на диск представляет собой сам файл, а не кешированную версию. В этом В этом случае вы можете создать интерфейс Cacheable, который говорит, какие методы класс, который кэшируется на диск, должен быть реализован, оставляя его к самому классу, чтобы реализовать их. Это имеет больше смысла, как классы, которые представляют различные виды данных, почти наверняка нуждаются реализовать свою схему кэширования (если есть) по-другому.

Каждый класс, который разрешает кэширование, будет определен как Класс реализует Cacheable, который вы можете проверить в ваш код. Менее опытные программисты могут проверить класс объекта они работают, получая класс и обрабатывая результат с большим заявлением переключателя. Это не правильный подход, потому что это означает, что вы предполагаете, что определенные объекты классов реализуют определенную функциональность, и если вы добавите новый класс в систему, вы необходимо изменить каждый оператор переключения в вашем программном обеспечении, чтобы принять его в учетная запись. Если вы используете интерфейс, вы можете проверить, является ли объект реализует этот интерфейс с ключевым словом instanceof.

if ($thisObject instanceof Cacheable)
{
// Manage item's cache
}

Этот подход лучше, потому что он устраняет оператор switch и таким образом облегчает обслуживание вашего программного обеспечения. Если вы добавите новый класс к системе, которая также реализует свою собственную схему кэширования, то вы просто нужно объявить, что он реализует Cacheable. Как интерфейс требует, чтобы все классы реализовали его для объявления указанных методов в интерфейсе вы можете быть уверены, что любой класс, который реализует Cacheable предоставит вам определенные методы для использования. Ваш код не нужно знать, как класс реализует эти методы, просто он их реализует.

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

0 голосов
/ 25 марта 2009

Когда в этом примере вы присмотритесь, вы увидите, что изменяется только свойство, используемое для поиска. Представляя это OO-способом, вы получаете класс, который я бы назвал «Lookup» (представляющий поиск, возможно, в SQL, может быть, на другом языке запросов: объект, который может возвращать rowId на основе некоторого свойства значение этого свойства.

Реальное поведенческое изменение будет в языке запросов. Так что если вы хотите создать абстрактный класс или интерфейс, он должен служить этой цели. Проблема различий в свойстве и значении может быть отделена путем добавления аргумента «свойство» к вызову запроса.

0 голосов
/ 25 марта 2009

На мой взгляд, это не нужно. Просто есть один репозиторий, который имеет различные функции поиска. Тогда просто используйте нужные вам функции, когда они нужны.

Однако интерфейсная часть станет полезной, только если у вас есть инструменты, которые ставят в очередь различные типы поиска. Тогда вы могли бы иметь фабрику, создающую различные типы классов поиска, которые все реализуют интерфейс. В этот момент вы можете перечислять свои классы поиска в очереди, приводить к интерфейсу и выполнять виртуальную функцию, указывающую на правильный тип поиска. Пример: ReturnDataObject GetItem(object param);

Кстати, есть и другие способы использования интерфейсов при извлечении данных. Это только первый пример, который приходит на ум.

0 голосов
/ 25 марта 2009

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

Я не думаю, что вам действительно нужно делать это таким образом. Вы можете просто сделать метод LocateBox общедоступным и заставить его вызывать частных помощников, в зависимости от того, какой поиск вы хотите выполнить. Обычно плохая идея чрезмерно усложнять структуру вашего класса только ради использования некоторых принципов проектирования ОО. Подождите, пока вы не найдете нужно для них, а затем рефакторинг соответствующим образом. Это поможет указать, что действительно необходимо и что является пустой тратой вашего времени.

Редактировать : Еще один подход, о котором я думал, - создать класс данных, обладающий свойствами, основанными на различных вещах, по которым вы могли бы искать. То есть. класс BoxSearchData, который имеет такие свойства, как UPC и т. д., а затем передает его в LocateBox () и при необходимости создает запрос на основе нулевых свойств. Это поможет вам построить поиск по нескольким критериям позже.

0 голосов
/ 25 марта 2009

Абстракция помогает, когда у вас есть несколько реализаций. И для будущего (надеясь, что новая реализация будет возникать). Интерфейс действует как контракт между клиентом и исполнителем. Это инвариант. Реализации могут добавлять любое количество методов по своему усмотрению. Есть ли у вас такие потребности?

Помогает ли это ответить на ваш вопрос?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...