Совместимо ли использование instanceOf в Java с принципом разработки «программа в интерфейс»? - PullRequest
8 голосов
/ 12 февраля 2011

Как вы знаете, принцип проектирования «программа для интерфейса» широко предпочитает супертипы, а не конкретные типы или реализации.

Соответствует ли это принципу использования instanceof в Java-программе для получения конкретного типа из супертипа?

В моем приложении Storehouse - это абстрактный класс супертипа с парой частных переменныхи общественные добытчики и сеттеры.

ConcreteStorehouseA наследуется от Storehouse и имеет множество конкретных методов и переменных.ConcreteStorehouseB похож, но отличается.

Мое приложение получает хранилище.Тем не менее, Storehouse не является полезным типом для работы.Поскольку в конкретных типах содержатся только действительно полезные методы, я использую instanceof следующим образом:

if (storehouse instanceof ConcreteStorehouseA) {
    ConcreteStorehouseA concreteStorehouseA = (ConcreteStorehouseA) storehouse;
    // perform operations on the concrete type's useful methods and variables

Совместимо ли использование instanceof с принципом?

Редактировать:

По сути, приложение представляет собой симулятор игры в кости для настольной RPG, Shadowrun.Конкретные типы - это разные типы тестов - Успешный тест, Оппозиционный тест, Расширенный тест - все они имеют очень разные факторы и параметры для успешной работы.Супертип по сути содержит пул костей!

Ответы [ 7 ]

10 голосов
/ 12 февраля 2011

Как правило, упомянутый вами принцип "программа для интерфейсов" может быть переведен в import только тип интерфейса, не зависящий во время компиляции от подклассов.

Таким образом, ответ на ваш вопрос будет определенно нет.Вы не программируете интерфейсы, так как вы приводите к конкретным типам.

8 голосов
/ 12 февраля 2011

Вы сказали это сами:

Мое приложение получает хранилище.Тем не менее, Storehouse не является полезным типом для работы.Потому что единственные действительно полезные методы содержатся в конкретных типах

Другими словами, ваша Storehouse абстракция ничего вам не покупает ... зачем она у вас?

Не могли бы вы создать абстрактные методы в Storehouse, реализованные в каждом конкретном классе, которые позволили бы вам обрабатывать конкретные типы таким же образом в вашем клиентском коде?Это цель абстракции.

2 голосов
/ 12 февраля 2011

Это не всегда грех.Предположим, что вы реализуете спецификацию, в которой говорится, что если x это A, сделайте это, иначе, если x это Y, сделайте это.Лучше, чтобы ваш код был похож на спецификацию.Искусственно разрезать его на мелкие кусочки и поместить в разные источники, это не только претенциозно, но и сложно, небезопасно, трудно понять и трудно поддерживать.

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

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

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

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

2 голосов
/ 12 февраля 2011

Не совсем. Если ваш метод имеет совершенно разное поведение в зависимости от типа, который он получает, то полиморфизм вам ничего не дает. Вы должны рассмотреть два отдельных перегруженных метода, один из которых принимает ConcreteStorehouseA в качестве аргумента, а другой - ConcreteStorehouseB.

1 голос
/ 12 февраля 2011

Похоже, что абстракция Storehouse на самом деле не совсем правильная абстракция в этом случае. Сам по себе тип не дает вам ничего.

Одна вещь, которая может помочь, это попытаться вообще не думать о ваших реализациях как о «типах». «Тип» - это абстракция, которую реализует класс. (По сути, разделите термины «класс» и «тип» в своем мышлении.) Таким образом, тип, с которым вы работаете, это Storehouse. ConcreteStorehouseA - это Storehouse, как и ConcreteStorehouseB. Таким образом, возникает вопрос, что такое Storehouse? Это тип, который определяет, что каждый из них.

В данном конкретном случае звучит так, что различные реализации Storehouse настолько различны (по крайней мере, в их текущей реализации), что на самом деле они не разделяют стоящую абстракцию. Абстрактный «тип» в данном случае просто обеспечивает некоторую общую функциональность посредством наследования, а не фактического абстрагирования типа.

Говоря иначе, похоже, что реализации Storehouse здесь являются классическим примером мотивационного плаката подстановки Лискова здесь: http://www.lostechies.com/blogs/derickbailey/archive/2009/02/11/solid-development-principles-in-motivational-pictures.aspx

1 голос
/ 12 февраля 2011

Может быть трудно убедиться без понимания того, какие операции вы выполняете, но более элегантный дизайн - это то, чтобы StoreHouse определял сигнатуры методов для различных «операций». Затем вместо проверок if (instanceof) вы просто выполняете операции, а конкретные хранилища реализуют эти операции.

public abstract class Storehouse
//add these definitions;
public void operation1();
public void operation2();

public class ConcreteStorehouseA

public void operation1() {
   //do operation
}

public void operation2() {
   //do operation
}

public class ConcreteStorehouseB

public void operation1() {
   //do operation
}

public void operation2() {
   //do operation
}

В вашем телефонном коде вместо:

if (storehouse instanceof ConcreteStorehouseA) {
    ConcreteStorehouseA concreteStorehouseA = (ConcreteStorehouseA) storehouse;
    // perform operations
} else if (storehouse instanceof ConcreteStorehouseB) {
    ConcreteStorehouseB concreteStorehouseB = (ConcreteStorehouseB) storehouse;
    // perform operations
}

Затем вы можете использовать полиморфизм для выполнения операций, не заботясь о том, какая реализация выполняется.

storehouse.operation1();
storehouse.operation2();

где concreteStorehouseA и ConcreteStorehouseB определили реализации для этих операций.

0 голосов
/ 12 февраля 2011

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

Существуют различные способы борьбы с этим, среди которых:

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