2015-10-02 192 views
0

我有時會遇到這種情況,不確定我是否使用了錯誤的方法,或者我不知道如何解決它。工廠模式和泛型

比方說,我有兩個階級,兩條豆這樣的:

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

我想打一個通用的抽象類,所以我可以從ClassOneClassTwo它,一個抽象的豆與提取一些邏輯常見的方法還有:

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> 

而我幾乎卡在那裏。我想我理解這個錯誤,但是,那麼是否有可能創建這樣一個工廠類試圖避免鑄件

我也檢查了this post,但不能完全理解它如何幫助我。

編輯:訪問者模式

好了,我已經試過在previos崗位描述訪問者模式:

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.StackOverflowError 
    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) 
    ... 

我可以看到爲什麼會發生這種情況,我錯過了什麼嗎?

+0

當你在'ClassOne'裏面調用'super(bean)'時 - 你調用哪個類的構造函數? – alfasin

+0

@alfasin我會調用'AbstractClass'類中的public AbstractClass(T bean)'構造函數。 – carcaret

+0

在第一個代碼示例中沒有'AbstractClass','ClassOne'沒有擴展任何類。 – alfasin

回答

1

從你提供你自己的問題,看到這個答案:https://stackoverflow.com/a/12630501/144302

同樣的原則也適用於您的問題:使用或者與重載方法

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

對於特定的優點和缺點,我會鼓勵你閱讀中的其他問題的全部答案(這是非常好的,我不不想盲目複製他人的作品)。

+0

我編輯了我的回答,添加了在其他線程中描述的訪問者模式方法,但現在我得到了一個'StackOverflowError'。我錯過了什麼嗎? – carcaret

+0

'AbstractClassVisitor'做什麼? – Stephan

+0

對不起,忘了包括該課程。 – carcaret

0

我認爲這是因爲構造函數參數public ClassOne(BeanOne bean)。您試圖提供作爲構造函數參數的BeanOne的父代AbstractBean。 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(); 
} 
+0

是的,這就是爲什麼我想知道是否有辦法在沒有鑄件的情況下完成這個任務。 – carcaret

+0

然後像上面那樣更改newInstance方法 – additionster

+0

但是這樣你只是刪除了我傳遞給工廠並實例化一個新的'bean'實例。我也許可以使用像'new BeanOne(bean)'這樣的拷貝構造函數。還有一個問題是我的警告'AbstractClass是一種原始類型。參考通用類型AbstractClass 應該是參數化的,可以通過添加這個'AbstractClass '來解決。不過,這是正確的方法,還是隻是一些黑客即使應該以另一種方式來完成這項工作? – carcaret