Статическая Фабрика: Проблема Проектирования Java
У меня есть базовый интерфейс, который определяет некоторые общие функциональные возможности. Теперь этот базовый интерфейс может быть реализован более чем 50 классами, каждый из которых имеет несколько различных дополнительных методов. Я хочу иметь статическую фабрику, которая будет возвращать экземпляр любого из 50 классов в зависимости от параметра, передаваемого этому методу статической фабрики.
public interface Base {
public void a();
public void b();
}
public class myclass implements Base {
// a and b implementation
public String c() {
}
public String d() {
}
}
public class secondclass implements Base {
// a and b implementation
public String e() {
}
public String f() {
}
}
Как я могу реализовать статический метод фабрики. Я не уверен в типе возврата
public synchronized static {return type} getInstance(String arg0) {
// do something and return any one class based on arg0
}
Правки:
Сценарий
Если переданный параметр равен Триста
Я хочу вернуть объект класса myclass
Если параметр равен 900
Я хочу вернуть объект класса secondclass
И так далее.
иметь так много условий неосуществимо.
НЕ ДЕЛАТЬ
public synchronized static {return type} getInstance(String arg0) {
// do something and return any one class based on arg0
if(arg0.equals("300")) {
return new myclass();
}
}
Причина:
Это не будет продаваться. Я разрабатываю публичный API, и список классов может увеличиться до 100 или может быть 500.
Надеюсь, теперь мой вопрос более ясен.
Обновление:
Очень полезные моменты, выделенные здесь, и это то, о чем я подумал
public abstract class Base {
public abstract void a();
public abstract void b();
public synchronized staticabstract Base getInstance(String arg0);
}
public class myclass extends Base {
private myclass() {} // private constructor not publicly instantiate
// a and b implementation
public void c();
public void d();
@Override
public synchronized static abstract Base getInstance(String arg0) {
if(arg0.equalsIgnoreCase("300")) { // only 1 if condition
return new myclass();
}
}
}
public class secondclass extends Base {
private secondclass() {} // private constructor not publicly instantiate
// a and b implementation
public void e();
public void f();
@Override
public synchronized static abstract Base getInstance(String arg0) {
if(arg0.equalsIgnoreCase("900")) { // only 1 if condition
return new secondclass();
}
}
}
Client side:
one applicaiton
Base b=Base.getInstance(300);
if(b instanceof myclass) {
}
second application
Base b=Base.getInstance(900);
if(b instanceof secondclass) {
}
3 ответов:
Лучшим подходом было бы обобщение статического метода:
Таким образом, теперь методstatic <T extends Base> T create(Class<T> type){ // create concrete instance of type T and return it }createпараметризуется реальным конкретным типом объектаClass. Вы можете использоватьtypeдля создания соответствующего подтипа, либо с помощью отражения, либо с помощью вложенных операторовif.Использование дженериков имеет то преимущество, что дает вам сильную безопасность типа бесплатно, так что вы можете избежать непроверенных бросков и идти домой после работы без забот.
EDIT : в качестве примера, если у вас был конструктор no-arg в каждом подклассе можно реализовать следующим образом:
return type.newInstance();EDIT 2 : подводя итог дискуссии, если фабрика не может принять тип или логику для создания объекта, зависящего нетривиальным образом от значения аргумента, единственным вариантом является следующее:
static Base create(String someParameter){ // create the concrete class and return it }И клиентский код будет выглядеть так:
Base b = create("myArgument"); if(b instanceof SomeDerived){ SomeDerived d = (SomeDerived) b; // use d } else if(b instanceof OtherDerived){ // you get the idea }Не идеально, но нет способа обобщить метод
createбез экземпляраClass<? extends Base>.
Одна из важных причин использования статической фабрики над конструкторами (цитата из эффективной Java):
Третье преимущество статических фабричных методов состоит в том, что, в отличие от конструкторы, они могут возвращать объект любого подтипа своего возврата типТаким образом, по существу, это может дать вам возможность написать что-то вроде:
Base x = Factory.getInstance(TypeX.class); x.methodOfBase();Где
TypeXможет быть полностью скрыт и иметь частный конструктор.Возможно, вы захотите взглянуть в
java.util.Collectionsреализации API, например, рассмотрим метод статической фабрики:public static <T> List<T> synchronizedList(List<T> list)Как вы видите, возвращаемый тип является интерфейсом , и поэтому возвращаемый объект(некоторая скрытая реализация
List) может использоваться только в качестве списка.Итак, если вы хотите использовать методы
x1(),x2()которые являются исключительными для подтипаTypeXи не принадлежат интерфейсуBase, вам все равно придется привести свой объект кTypeX.
В этом случае вы можете создать экземплярTypeXнепосредственно через конструктор (сохраняя его открытым), как статическая фабрика не даст вам ничего.Вы также можете взглянуть на другие 3 причины для использования
static factoryнадconstructorsв книге и проверить, что ни одна из них не применима к тому, что вы описали в своем вопросе до сих пор.
Возвращаемым типом будет интерфейс.
Например:
public synchronized static Base getInstance(String arg0) { if(arg0.equals("myClass")) return new myClass(); else if (arg0.equals("secondClass")) return new secondClass(); }Вы бы назвали конкретные методы так:
Base instance = getInstance("myClass"); ((myClass) instance).c();Вы также можете бросить его непосредственно:
myClass instance = (myClass) getInstance("myClass"); instance.c();
Comments