Проект C#, но он может применяться к любым языкам OO. 3 интерфейсов взаимодействующие:OOP, дизайн интерфейса и инкапсуляция
public interface IPublicData {}
public /* internal */ interface IInternalDataProducer { string GetData(); }
public interface IPublicWorker {
IPublicData DoWork();
IInternalDataProducer GetInternalProducer();
}
public class Engine {
Engine(IPublicWorker worker) {}
IPublicData Run() {
DoSomethingWith(worker.GetInternalProducer().GetData());
return worker.DoWork();
}
}
Ясно Engine
параметрический в фактическом работнике, который делает работу. Другим источником параметризации является то, как мы производим «внутренние данные» через IInternalDataProducer
. Эта реализация требует, чтобы IInternalDataProducer
был общедоступным, поскольку он является частью декларации открытого интерфейса IPublicWorker
. Тем не менее, я бы хотел, чтобы он был внутренним, поскольку он используется только движком.
Решение состоит в том, чтобы сделать внутренние данные сами, но это не очень элегантно, так как существует всего несколько способов его создания (в то время как есть много других реализаций рабочих), поэтому приятно делегировать пару отдельные конкретные классы. Кроме того, IInternalDataProducer
используется в других местах внутри двигателя, поэтому для двигателя полезно обходить фактический объект.
Также не вариант (очевидно) передать экземпляр IInternalDataProducer
непосредственно на конструктор Engine
. Мы не хотим, чтобы пользователи библиотеки (Engine
) знали о производителе данных. Обязанность работника - объявлять (производить), какой производитель данных следует использовать.
Я ищу элегантный, безопасный тип, идеи/узоры. Приветствие :-)
EDIT: На основании ответа Джеффа, вот решение:
Это не идеально, потому что интерфейс по-прежнему «грязный» с GetData()
, которые пользователь не должен видеть (но мой оригинальный интерфейс тоже был грязным), а потому, что он приводит к «дублированию интерфейса» (GetData()
объявлен в двух интерфейсах) - у вас не может быть всего.
Следующая проблема заключается в том, чтобы очистить GetData()
из интерфейса IPublicWorker
тогда :)
public interface IPublicData {}
internal /* ! */ interface IInternalDataProducer { string GetData(); }
public interface IPublicWorker {
IPublicData DoWork();
string GetData();
}
public class APublicWorker : IPublicWorker {
private IInternalDataProducer dataProducer;
public APublicWorker() {
dataProducer = new SomeDataProducer();
}
IPublicData DoWork() { ... }
string GetData() {
/* Delegation! */
return dataProducer.GetData();
/* ********* */
}
}
public class Engine {
Engine(IPublicWorker worker) {}
IPublicData Run() {
DoSomethingWith(worker.GetData());
return worker.DoWork();
}
}
Вам не хватает члена IPublicWorker внутри движка, но nit-picks в сторону, именно это я и рекомендовал бы. –
Спасибо, Джефф. К сожалению, это именно то, чего я пытаюсь избежать. Мы не хотим, чтобы пользователи библиотеки (движка) знали о производителе данных. Обязанность работника - объявлять (производить), какой производитель данных следует использовать, и это должно быть прозрачным для пользователя. – Mau
@Mau - Я понимаю, вы пытаетесь избежать этого, но я пытаюсь убедить вас, что это будет плохой идеей! Мы могли бы немного изменить ситуацию, чтобы придать производителю данных вместо рабочего (вместо этого это звучит как не тот владелец, учитывая то, что вы описали), но это просто переносит проблему на рабочего. –