Я работаю над дизайном API, и есть кое-что о Java и полиморфизме, о котором я не думал до сих пор. Если я создаю API, как это:Java, полиморфизм, статическая типизация и шаблон «QueryInterface»
interface FooFactory
{
public Foo getFoo();
}
interface Foo
{
public void sayFoo();
}
тогда единственное, что моя FooFactory
реализация может полагаться, чтобы обеспечить это Foo
реализации. Если я решу предоставить некоторые усовершенствованные методы, например:
interface EnhancedFoo extends Foo
{
public void patHeadAndRubBelly();
}
class EnhancedFooImpl implements EnhancedFoo
{
... implementation here ...
}
class EnhancedFooFactoryImpl implements FooFactory
{
@Override public EnhancedFoo getFoo() { return new EnhancedFooImpl(); }
}
и единственный способ мои клиенты API могут использовать интерфейс EnhancedFoo
, если они получают интерфейс Foo
и попытаться привести его в качестве EnhancedFoo
.
Я помню, как Microsoft обрабатываются COM в интерфейсе IUnknown
:
HRESULT QueryInterface(
[in] REFIID riid,
[out] void **ppvObject
);
Идея заключается в том, что вы передаете в GUID для интерфейса вы хотите, если это удастся, вы получите обратно указатель, который гарантирует вам может безопасно отнести его к интерфейсу, который вы искали.
я мог бы сделать что-то подобное в типизированном образе с Java:
interface FooFactory
{
public <T extends Foo> T getFoo(Class<T> fooClass);
}
где я обеспечить реализацию по запросу, который либо возвращает экземпляр требуемого подинтерфейся или возвращают нулевое значение, если ни один не доступно.
Мой вопрос, является:
- является образцом QueryInterface разумным?
- Должен ли я просто использовать литье?
- или это единственный правильный способ обработки полиморфизма в API, чтобы ограничить клиентов строго использованием простых методов? (Например, способы, описанные в
Foo
в моем примере, а не любыеEnhancedFoo
методы)
Разъяснение: Реализация завод не будет известен клиентским кодом. (Предположим, что он использует инъекцию зависимостей или некоторую архитектуру поставщика услуг, такую как java ServiceLoader
или NetBeans Lookup
.) Так что, как клиент, я не знаю, что доступно. Завод может иметь доступ к нескольким производным от Foo
, и я хочу, чтобы клиент мог запросить набор функций, который он хочет, и либо он получит это, либо ему придется вернуться на базовую функциональность Foo
.
Я полагаю, что для меня трудная часть заключается в том, что здесь существует зависимость от времени выполнения ... чистый статический типный подход, когда все исправлено во время компиляции, означает, что я могу только зависеть от этой базовой функции Foo
. Этот подход мне знаком, но потом я теряю возможности для улучшенных функций. В то время как более динамичный/оппортунистический подход - это то, что может воспользоваться этими функциями, но я не уверен в правильном способе создания системы, которая ее использует.
Тип вывода был улучшен в Java 8. – assylias
Хм ... подход к исключению является нормальным для Python, но кажется неприемлемым для Java. –
Я бы сказал, что это вполне уместно - лучше, чем проверка нуля – Arkadiy