【问题标题】:How to delegate instantiation of constructor by classtype?如何通过类类型委托构造函数的实例化?
【发布时间】:2015-04-02 16:46:01
【问题描述】:

我有几个扩展BaseClass 的类。现在我想在DelegatorContext中静态定义一个活动类,每个对象的创建都应该基于活动上下文。

例子:

class BaseClass {
    String firstname, lastname;
}

class FirstClas extends BaseClass {}
class SndClass extends BaseClass {}

class DelegatorContext {
    public static BaseClass activeClass;
}

class Delegator {
    BaseClass create(String firstname, String lastname) {
        return DelegatorContext.activeClass instanceof FirstClass
          ? new FirstClass(firstname, lastname) : new SndClass(firstname, lastname);
    }
}

如果引入更多实体以扩展 BaseClass,该示例将获得更多样板。

对于我的这类问题有更好的模式吗?甚至可能使用 Java8 和Functions?还是泛型?

我正在使用这个构造来在运行时切换实现...

【问题讨论】:

  • 您可能应该使用Class 对象,而不是所需类的实际实例。但是你必须确保每个子类都有一个双字符串参数的构造函数,而你在上面的例子中没有。

标签: java generics java-8


【解决方案1】:

我猜,你的意思是这样的:

interface BaseClassFactory {
    BaseClass create(String firstname, String lastname);
}
class DelegatorContext {
    public static BaseClassFactory active;
}

DelegatorContext.active=FirstClass::new;

DelegatorContext.active=SndClass::new;

它要求所有子类都有一个签名相同的构造函数,匹配工厂接口的签名(有趣的是给this recent question一个例子)

你并不真正需要另一个工厂类,但为了完整起见,它会是:

class Delegator {
    BaseClass create(String firstname, String lastname) {
        return DelegatorContext.active.create(firstname, lastname);
    }
}

【讨论】:

  • 不幸的是 FirstClass::new 给出以下错误:The target type of this expression must be a functional interface
  • 检查FirstClass::new 是否分配给BaseClassFactory 类型的变量,如我的回答所示。 BaseClassFactory 应该由一个 abstract 方法组成,如图所示;如果不符合条件,您可以添加@FunctionalInterface 以获得编译器反馈。
  • 感谢您的解释。我现在明白了,它按预期工作!
【解决方案2】:

您可以使用作为BaseClass 子类的类型参数使DelegatorContext 泛型。

此外,activeClass 不应该是 static,并且应该引入一个额外的 Class<T> 成员来保存有关 activeClassClass 信息。

它将用于实例化正确的子类:

class DelegatorContext<T extends BaseClass> {
    private Class<T> clazz;

    public T activeClass;

    private DelegatorContext(Class<T> clazz) { 
         this.clazz = clazz;
    }

    public T createInstance(String firstname, String secondname) {
        activeClass = clazz.newInstance();
        activeClass.setFirstName(firstname);
        activeClass.setSecondName(secondname);
        return activeClass;
    }

    public static <T extends BaseClass> DelegatorContext<T> of(Class<T> clazz) {
        return new DelegatorContext<T>(clazz);
    }
}

有了这个,你可以这样做:

<T extends BaseClass> T create(Class<T> clazz, String firstname, String lastname) {
    return DelegatorContext.of(clazz).createInstance(firstname, lastname);
}

【讨论】:

  • 可以用这个在运行时切换活动类吗?
  • 是的,您始终可以为clazz 提供设置器。但是,在更改活动类时,您必须确保 activeClass 正确更改。所以是的,这是可能的。
  • 我会这样做 Java 8...
【解决方案3】:

据我所知,您最好在这里使用枚举:

enum DelegatorContext {
    First {
        @Override
        BaseClass instantiate(String firstName, String lastName) {
            return new FirstClass(firstName, lastName);
        }
    },
    Second{
        @Override
        BaseClass instantiate(String firstName, String lastName) {
            return new SecondClass(firstName, lastName);
        }
    };

    static Context defaultContext;
    abstract BaseClass instantiate(String firstName, String lastName);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-29
    • 2017-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-12
    相关资源
    最近更新 更多