工厂模式和泛型
Factory pattern and Generics
我有时 运行 遇到这种情况,但不确定我是否使用了错误的方法,或者我只是不知道如何解决它。
假设我有两个 classes 和两个像这样的 bean:
public class BeanOne {
public void methodBeanOne() {
//...
}
}
public class BeanTwo {
public void methodBeanTwo() {
//...
}
}
public class ClassOne {
private BeanOne bean;
public ClassOne(BeanOne bean) {
this.bean = bean;
}
public void methodclassOne() {
bean.methodBeanOne();
}
}
public class ClassTwo {
private BeanTwo bean;
public ClassTwo(BeanTwo bean) {
this.bean = bean;
}
public void methodClassTwo() {
bean.methodBeanTwo();
}
}
我想做一个通用的抽象 class ,所以我可以从 ClassOne
和 ClassTwo
中提取一些逻辑,以及一个具有通用方法的抽象 bean:
public abstract class AbstractBean {
public void commonMethod() {
//...
}
}
public class BeanOne extends AbstractBean {
public void methodBeanOne() {
//...
}
}
public class BeanTwo extends AbstractBean {
public void methodBeanTwo() {
//...
}
}
public abstract class AbstractClass<T extends AbstractBean> {
protected T bean;
public AbstractClass(T bean) {
this.bean = bean;
}
public void commonClassMethod(){
bean.commonMethod();
}
}
public class ClassOne extends AbstractClass<BeanOne> {
public ClassOne(BeanOne bean) {
super(bean);
}
public void methodclassOne() {
bean.methodBeanOne();
}
}
public class ClassTwo extends AbstractClass<BeanTwo> {
public ClassTwo(BeanTwo bean) {
super(bean);
}
public void methodClassTwo() {
bean.methodBeanTwo();
}
}
到目前为止,还不错。
下一步是创建一个工厂来获得一个基于 enum
的实现,例如,这是我开始出错的地方:
public class ClassFactory {
public enum MyEnum {
ONE, TWO;
}
private ClassFactory() {
}
public static AbstractClass newInstance(MyEnum value, AbstractBean bean) {
switch(value){
case ONE:
return new ClassOne(bean);
case TWO:
return new ClassTwo(bean);
default:
throw new IllegalArgumentException();
}
}
}
这会产生以下编译错误:
The constructor ClassOne(AbstractBean) is undefined
The constructor ClassTwo(AbstractBean) is undefined
我也试过:
public class ClassFactory {
public enum MyEnum {
ONE, TWO;
}
private ClassFactory() {
}
public static <T extends AbstractBean> AbstractClass<T> newInstance(MyEnum value, T bean) {
switch(value){
case ONE:
return new ClassOne(bean);
case TWO:
return new ClassTwo(bean);
default:
throw new IllegalArgumentException();
}
}
}
但后来我得到:
Type mismatch: cannot convert from ClassOne to AbstractClass<T>
Type mismatch: cannot convert from ClassTwo to AbstractClass<T>
我几乎被困在那里。我想我理解这个错误,但是,是否可以创建这样一个工厂class 试图避免铸造?
我也检查过 this post,但不能完全理解它对我有何帮助。
编辑:访客模式
好的,所以我尝试了前面描述的访问者模式 post:
public interface Visitor<T> {
T visit(BeanOne bean);
T visit(BeanTwo bean);
}
public abstract class AbstractBean {
public void commonMethod() {
// ...
}
public abstract <T> T accept(Visitor<T> visitor);
}
public class BeanOne extends AbstractBean {
public void methodBeanOne() {
// ...
}
@Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
}
public class BeanTwo extends AbstractBean {
public void methodBeanTwo() {
// ...
}
@Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
}
public class ClassFactory {
private ClassFactory() {
}
public static AbstractClass<? extends AbstractBean> newInstance(AbstractBean bean) {
return bean.accept(new AbstractClassVisitor());
}
}
public class AbstractClassVisitor implements Visitor<AbstractClass<? extends AbstractBean>> {
@Override
public AbstractClass<? extends AbstractBean> visit(BeanOne bean) {
return ClassFactory.newInstance(bean);
}
@Override
public AbstractClass<? extends AbstractBean> visit(BeanTwo bean) {
return ClassFactory.newInstance(bean);
}
}
但是这样使用它:
AbstractBean bean = new BeanOne();
AbstractClass<? extends AbstractBean> clazz = ClassFactory.newInstance(bean);
clazz.commonClassMethod();
我遇到以下异常:
Exception in thread "main" java.lang.WhosebugError
at test.AbstractClassVisitor.<init>(AbstractClassVisitor.java:3)
at test.ClassFactory.newInstance(ClassFactory.java:9)
at test.AbstractClassVisitor.visit(AbstractClassVisitor.java:7)
at test.AbstractClassVisitor.visit(AbstractClassVisitor.java:1)
at test.BeanOne.accept(BeanOne.java:10)
at test.ClassFactory.newInstance(ClassFactory.java:9)
at test.AbstractClassVisitor.visit(AbstractClassVisitor.java:7)
at test.AbstractClassVisitor.visit(AbstractClassVisitor.java:1)
at test.BeanOne.accept(BeanOne.java:10)
at test.ClassFactory.newInstance(ClassFactory.java:9)
at test.AbstractClassVisitor.visit(AbstractClassVisitor.java:7)
at test.AbstractClassVisitor.visit(AbstractClassVisitor.java:1)
at test.BeanOne.accept(BeanOne.java:10)
...
我明白为什么会这样了,我是不是漏掉了什么?
我认为是因为构造函数参数public ClassOne(BeanOne bean)
。您尝试提供 AbstractBean
作为构造函数参数,它是 BeanOne
的父级。 Java 只允许对象扩大而不是缩小。尝试将父对象类型转换为特定的子对象,如下所示:
public static AbstractClass newInstance(MyEnum value, AbstractBean bean) {
switch(value):
case ONE:
return new ClassOne((BeanOne)bean);
case TWO:
return new ClassTwo((BeanTwo)bean);
default:
throw new IllegalArgumentException();
}
但请确保在调用 newInstance
方法时提供正确的对象实例。
否则可能会发生 ClassCastException。
编辑:
public static AbstractClass newInstance(MyEnum value) {
switch(value):
case ONE:
return new ClassOne(new BeanOne());
case TWO:
return new ClassTwo(new BeanTwo());
default:
throw new IllegalArgumentException();
}
根据您自己提出的问题,看到这个答案:
同样的原则也适用于您的问题:使用方法重载的工厂
public class ClassFactory {
private ClassFactory() {
}
public static AbstractClass<BeanOne> newInstance(BeanOne bean) {
return new ClassOne(bean);
}
public static AbstractClass<BeanTwo> newInstance(BeanTwo bean) {
return new ClassTwo(bean);
}
}
或者,正如答案中所指出的那样,应用像双重分派这样的原则,将方法 AbstractClass<T> newInstance()
添加到 AbstractBean
并在每个专业化中适当地实现它。例如
class BeanOne { /* ... */
public AbstractBean<BeanOne> newInstance() {
return ClassFactory.newInstance(this);
}
}
终于可以在ClassFactory
中加入下面的方法了
public static <T> AbstractClass<T> newInstance(AbstractBean<T> bean) {
return bean.newInstance();
}
对于具体的优缺点,我建议你阅读另一个问题中的整个答案(非常好,我不想盲目复制别人的作品)。
我有时 运行 遇到这种情况,但不确定我是否使用了错误的方法,或者我只是不知道如何解决它。
假设我有两个 classes 和两个像这样的 bean:
public class BeanOne {
public void methodBeanOne() {
//...
}
}
public class BeanTwo {
public void methodBeanTwo() {
//...
}
}
public class ClassOne {
private BeanOne bean;
public ClassOne(BeanOne bean) {
this.bean = bean;
}
public void methodclassOne() {
bean.methodBeanOne();
}
}
public class ClassTwo {
private BeanTwo bean;
public ClassTwo(BeanTwo bean) {
this.bean = bean;
}
public void methodClassTwo() {
bean.methodBeanTwo();
}
}
我想做一个通用的抽象 class ,所以我可以从 ClassOne
和 ClassTwo
中提取一些逻辑,以及一个具有通用方法的抽象 bean:
public abstract class AbstractBean {
public void commonMethod() {
//...
}
}
public class BeanOne extends AbstractBean {
public void methodBeanOne() {
//...
}
}
public class BeanTwo extends AbstractBean {
public void methodBeanTwo() {
//...
}
}
public abstract class AbstractClass<T extends AbstractBean> {
protected T bean;
public AbstractClass(T bean) {
this.bean = bean;
}
public void commonClassMethod(){
bean.commonMethod();
}
}
public class ClassOne extends AbstractClass<BeanOne> {
public ClassOne(BeanOne bean) {
super(bean);
}
public void methodclassOne() {
bean.methodBeanOne();
}
}
public class ClassTwo extends AbstractClass<BeanTwo> {
public ClassTwo(BeanTwo bean) {
super(bean);
}
public void methodClassTwo() {
bean.methodBeanTwo();
}
}
到目前为止,还不错。
下一步是创建一个工厂来获得一个基于 enum
的实现,例如,这是我开始出错的地方:
public class ClassFactory {
public enum MyEnum {
ONE, TWO;
}
private ClassFactory() {
}
public static AbstractClass newInstance(MyEnum value, AbstractBean bean) {
switch(value){
case ONE:
return new ClassOne(bean);
case TWO:
return new ClassTwo(bean);
default:
throw new IllegalArgumentException();
}
}
}
这会产生以下编译错误:
The constructor ClassOne(AbstractBean) is undefined
The constructor ClassTwo(AbstractBean) is undefined
我也试过:
public class ClassFactory {
public enum MyEnum {
ONE, TWO;
}
private ClassFactory() {
}
public static <T extends AbstractBean> AbstractClass<T> newInstance(MyEnum value, T bean) {
switch(value){
case ONE:
return new ClassOne(bean);
case TWO:
return new ClassTwo(bean);
default:
throw new IllegalArgumentException();
}
}
}
但后来我得到:
Type mismatch: cannot convert from ClassOne to AbstractClass<T>
Type mismatch: cannot convert from ClassTwo to AbstractClass<T>
我几乎被困在那里。我想我理解这个错误,但是,是否可以创建这样一个工厂class 试图避免铸造?
我也检查过 this post,但不能完全理解它对我有何帮助。
编辑:访客模式
好的,所以我尝试了前面描述的访问者模式 post:
public interface Visitor<T> {
T visit(BeanOne bean);
T visit(BeanTwo bean);
}
public abstract class AbstractBean {
public void commonMethod() {
// ...
}
public abstract <T> T accept(Visitor<T> visitor);
}
public class BeanOne extends AbstractBean {
public void methodBeanOne() {
// ...
}
@Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
}
public class BeanTwo extends AbstractBean {
public void methodBeanTwo() {
// ...
}
@Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
}
public class ClassFactory {
private ClassFactory() {
}
public static AbstractClass<? extends AbstractBean> newInstance(AbstractBean bean) {
return bean.accept(new AbstractClassVisitor());
}
}
public class AbstractClassVisitor implements Visitor<AbstractClass<? extends AbstractBean>> {
@Override
public AbstractClass<? extends AbstractBean> visit(BeanOne bean) {
return ClassFactory.newInstance(bean);
}
@Override
public AbstractClass<? extends AbstractBean> visit(BeanTwo bean) {
return ClassFactory.newInstance(bean);
}
}
但是这样使用它:
AbstractBean bean = new BeanOne();
AbstractClass<? extends AbstractBean> clazz = ClassFactory.newInstance(bean);
clazz.commonClassMethod();
我遇到以下异常:
Exception in thread "main" java.lang.WhosebugError
at test.AbstractClassVisitor.<init>(AbstractClassVisitor.java:3)
at test.ClassFactory.newInstance(ClassFactory.java:9)
at test.AbstractClassVisitor.visit(AbstractClassVisitor.java:7)
at test.AbstractClassVisitor.visit(AbstractClassVisitor.java:1)
at test.BeanOne.accept(BeanOne.java:10)
at test.ClassFactory.newInstance(ClassFactory.java:9)
at test.AbstractClassVisitor.visit(AbstractClassVisitor.java:7)
at test.AbstractClassVisitor.visit(AbstractClassVisitor.java:1)
at test.BeanOne.accept(BeanOne.java:10)
at test.ClassFactory.newInstance(ClassFactory.java:9)
at test.AbstractClassVisitor.visit(AbstractClassVisitor.java:7)
at test.AbstractClassVisitor.visit(AbstractClassVisitor.java:1)
at test.BeanOne.accept(BeanOne.java:10)
...
我明白为什么会这样了,我是不是漏掉了什么?
我认为是因为构造函数参数public ClassOne(BeanOne bean)
。您尝试提供 AbstractBean
作为构造函数参数,它是 BeanOne
的父级。 Java 只允许对象扩大而不是缩小。尝试将父对象类型转换为特定的子对象,如下所示:
public static AbstractClass newInstance(MyEnum value, AbstractBean bean) {
switch(value):
case ONE:
return new ClassOne((BeanOne)bean);
case TWO:
return new ClassTwo((BeanTwo)bean);
default:
throw new IllegalArgumentException();
}
但请确保在调用 newInstance
方法时提供正确的对象实例。
否则可能会发生 ClassCastException。
编辑:
public static AbstractClass newInstance(MyEnum value) {
switch(value):
case ONE:
return new ClassOne(new BeanOne());
case TWO:
return new ClassTwo(new BeanTwo());
default:
throw new IllegalArgumentException();
}
根据您自己提出的问题,看到这个答案:
同样的原则也适用于您的问题:使用方法重载的工厂
public class ClassFactory {
private ClassFactory() {
}
public static AbstractClass<BeanOne> newInstance(BeanOne bean) {
return new ClassOne(bean);
}
public static AbstractClass<BeanTwo> newInstance(BeanTwo bean) {
return new ClassTwo(bean);
}
}
或者,正如答案中所指出的那样,应用像双重分派这样的原则,将方法 AbstractClass<T> newInstance()
添加到 AbstractBean
并在每个专业化中适当地实现它。例如
class BeanOne { /* ... */
public AbstractBean<BeanOne> newInstance() {
return ClassFactory.newInstance(this);
}
}
终于可以在ClassFactory
public static <T> AbstractClass<T> newInstance(AbstractBean<T> bean) {
return bean.newInstance();
}
对于具体的优缺点,我建议你阅读另一个问题中的整个答案(非常好,我不想盲目复制别人的作品)。