Как отменить зависимость для класса Factory перенесена в библиотеку
Следующий код работает очень хорошо, когда все участвующие классы находятся в одном проекте (determineSubClass
является членом BaseClass
):
protected static BaseClass determineSubClass(String p1, int p2, Boolean p3) {
BaseClass baseObj = null;
if ( (baseObj = SubClassOne.ofType(p1, p2, p3)) != null )
return baseObj;
else if ( (baseObj = SubClassTwo.ofType(p1, p2, p3)) != null )
return baseObj;
else if ( (baseObj = SubClassThree.ofType(p1, p2, p3)) != null )
return baseObj;
else if ( (baseObj = SubClassFour.ofType(p1, p2, p3)) != null )
return baseObj;
else
return new SubClassDefault(p1, p2, p3);
}
Но теперь я хочу переместить BaseClass
в общий библиотечный проект, в котором SubClassOne
, SubClassTwo
, SubClassThree
а также SubClassFour
определяются не в библиотеке, а в приложениях, использующих эту библиотеку.
Я мог бы, конечно, двигаться BaseClass
вернуться к каждому приложению, использующему эту библиотеку, но мне интересно:
- Есть ли лучшее решение?
- Есть ли решение, которое позволило бы мне сохранить
BaseClass
в проекте библиотеки и избавить его от необходимости знать обо всех производных от него суперклассах?
РЕДАКТИРОВАТЬ (отвечая на вопрос @ahmet Alp Balkan ниже):
ofType()
каждого подкласса делает 2 вещи:
- Определяет, основываясь на содержимом строки p1 и других параметров p2 и p3, имеет ли подкласс, который должен быть создан, его тип.
- Если ответ положительный, он создает объект подкласса self. В противном случае возвращает ноль.
Что касается вашего второго вопроса, BaseClass
на данный момент содержит общие элементы данных и методы для всех подклассов и только этот единственный статический метод, который направлен на делегирование ответственности определения экземпляра подкласса, который будет создан.
Кстати, благодаря вашему вопросу я заметил ужасную опечатку в своем оригинальном сообщении: "SuperClassOne" должен быть "SubClassOne" и т. Д.
2 ответа
Ваша статика determineSubClass
Метод является заводским методом. Очевидно, он не должен находиться на BaseClass
, поскольку не только базовый класс не должен ничего знать о подклассах, но в вашем случае он ничего не может знать об этом, поскольку вы хотите найти базовый класс в другом проекте. Нет, этот метод должен находиться в фабричном классе, который отвечает за создание BaseClass
экземпляров. Что вы должны сделать, это определить интерфейс (или базовый тип) для создания BaseClass
экземпляры рядом с BaseType
и определяет реализацию в корне композиции вашего приложения. Когда у вас есть несколько приложений, они, вероятно, имеют разные наборы BaseClass
подтипы, поэтому у каждого приложения будет свой завод. Когда у вас есть эта конструкция, вы можете вводить фабрику в классы, которые нуждаются BaseClass
экземпляров.
Это может выглядеть примерно так:
// Shared library
public interface IBaseClassFactory
{
BaseClass CreateNew(String p1, int p2, Boolean p3);
}
public abstract class BaseClass
{
}
// Application code
public class SubClassOne : BaseClass
{
}
public class SubClassTwo : BaseClass
{
}
// Note that this consumer depends on IBaseClassFactory.
public class SomeConsumer
{
private IBaseClassFactory baseClassFactory;
public SomeConsumer(IBaseClassFactory factory)
{
this.baseClassFactory = factory;
}
public void Consume()
{
BaseClass instance = this.baseClassFactory
.CreateNew("foo", 0, false);
// use instance
}
}
// Composition root
class BaseClassFactory : IBaseClassFactory
{
public BaseClass CreateNew(String p1, int p2, Boolean p3)
{
BaseClass baseObj = null;
if ((baseObj = SubClassOne.ofType(p1, p2, p3)) != null)
return baseObj;
// etc
else
return new SubClassDefault(p1, p2, p3);
}
}
Это не очень хорошая практика, что базовый класс знает о своих суперклассах. Это нарушает примерно половину принципов ОО;).....
Я бы переместил метод в новый класс с именем HierarchyManager или что-то в этом роде, и у меня был бы этот метод. Вы могли бы даже построить некоторую иерархию там -> вы могли бы эффективно сделать этот метод "расширяемым" ....
Например, в библиотеке вы можете иметь:
BaseClass -> A, B (подклассы A, B BaseClass) и некоторый LibraryHierachyManager, обрабатывающий эти три класса...
а затем в приложении, используя его:
C, D (подклассы BaseClass или A или B)
и некоторые ApplicationHieararchyManager делают:
public static BaseClass determineSubClass(String p1, int p2, Boolean p3) {
if (baseObj = C.ofType(.....) {
....
} else {
return LibraryHierarchyManager.determineSubClass(p1,p2, p3);
}
}