首页 文章

静态工厂:Java设计问题

提问于
浏览
4

我有一个Base接口,定义了一些常用功能 . 现在,这个基本接口可以由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
  }

编辑:一个场景

如果传递的参数是300我想返回类 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 回答

  • 4

    更好的方法是生成静态方法:

    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
    }
    

    不理想,但如果没有 Class<? extends Base> 的实例,就无法生成 create 方法 .

  • 3

    使用静态工厂而不是构造函数的相关原因之一(引自Effective Java):

    静态工厂方法的第三个优点是,与构造函数不同,它们可以返回其返回类型的任何子类型的对象

    所以,基本上它可以让你有能力写下这样的东西:

    Base x = Factory.getInstance(TypeX.class); 
    x.methodOfBase();
    

    其中 TypeX 可以完全隐藏并具有私有构造函数 .

    您可能需要查看 java.util.Collections API实现,例如考虑静态工厂方法:

    public static <T> List<T> synchronizedList(List<T> list)
    

    如您所见,返回类型是一个接口,因此返回的对象(某些隐藏的 List 实现)只能用作List .

    因此,如果您想使用 x1()x2() 这些属于子类型 TypeX 并且不属于 Base 接口的方法,则无论如何都必须将对象转换为 TypeX .
    在这种情况下,您可以通过构造函数直接实例化 TypeX (通过保持公共),因为静态工厂不会给您任何东西 .

    您可能还想查看书中使用 static factory 而不是 constructors 的其他3个理由,并确认它们中没有适用于您目前在问题中描述的内容 .

  • 0

    返回类型将是接口 .

    例如:

    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();
    

相关问题