Статическая Фабрика: Проблема Проектирования 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) {

}
688   3  

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

    Ничего не найдено.