Совместимо ли использование instanceOf в Java с принципом разработки "программа в интерфейс"?

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

Согласуется ли это с принципом использования 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 ответов

Решение

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

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

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

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

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

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

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

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

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

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

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

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

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

Это звучит как 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

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

Есть различные способы справиться с этим, среди которых:

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