2012-02-14 84 views
2

我正在爲Java中的外部程序製作一個新的腳本生成器。這種語言支持變量,但它是一種無類型的語言。這是我最初寫的代碼的一個例子:Java - 識別值類型的模式

public class Var 
{ 
    private String name; 
    private String type; 
    private float defaultValue; 
    private float lowerBound; 
    private float upperBound; 
    private float value; 
    private LinkedList<Float> valuesConstraint; 
    private String description; 
    private Category category; 
    private LinkedList<CvarDependency> dependencies; 
    ... 
} 

通常VAR類型是浮點型,但它可以是還一個bool [0 | 1],字符串或int。 所以我最終做出這個實現:

abstract class Var 
{ 
    private String name; 
    ... 
} 

public class IntVar extends Var 
{ 
    private int value; 
    private int defaultValue; 
    private int lowerBound; //-infinite 
    private int upperbound; //+infinite 
    ... 
} 

public class FloatVar extends Var 
{ 
    private float value; 
    private float defaultValue; 
    private float lowerBound; //-infinite 
    private float upperbound; //+infinite 
    ... 
} 

public class StringVar extends Var 
{ 
    private String value; 
    private String defaultValue; //empty string 
    ... 
} 

public class BoolVar extends Var 
{ 
    private boolean value; 
    private boolean defaultValue; 
    private boolean lowerBound; //false <-> 0 
    private boolean upperbound; //true <-> 1 
    ... 
} 

現在我必須對那些瓦爾存儲到一個LinkedList,但是當我要讀的內容我怎麼管理的正確鑄造?我讀過使用這種方法不是一個好習慣:

Var var = Manager.getVar("namevar"); 
if(var.getClass().getName().equals("StringVar")) 
    ... 
else if(var.getClass().getName().equals("IntVar")) 
    ... 
else if(var.getClass().getName().equals("FloatVar")) 
    ... 
else if(var.getClass().getName().equals("BoolVar")) 
    ... 

任何提示能更好地處理這個問題嗎?

+0

我會爲每個'Var'建議一個'Visitor'模式。這樣,訪問者就知道如何進行鑄造。 – 2012-02-14 11:54:48

+0

好吧,這是我需要的模式。請發表評論作爲答案,這樣我可以把它放在堆棧的回覆中! – Otacon 2012-02-14 12:03:34

+0

你可以使用instanceOf運算符嗎? – basav 2012-02-14 12:05:49

回答

0

不要拿名字之類的,比較類:

if(var.getClass().equals(IntVar.class)) { 
    IntVar intVar = (IntVar) var; 
    ... 

你也可以使用var instanceof IntVar,但如果你寫一個擴展IntVar一類,可能會造成問題。

+0

不錯,謝謝,但這是一個「良好做法」? :) – Otacon 2012-02-14 11:52:11

+0

是的,是的。但在比較之前,你應該檢查var不是'null'。 – Stephan 2012-02-14 11:53:37

+0

當然和thx;) – Otacon 2012-02-14 11:55:47

0

您可以使用一個通用的類型,但我不知道你需要與成員做什麼...

public class Var<T extends Comparable<T>> 
{ 
    private String name; 
    private String type; 
    private T defaultValue; 
    private T lowerBound; 
    private T upperBound; 
    private T value; 
    private LinkedList<T> valuesConstraint; 
    private String description; 
    private Category category; 
    private LinkedList<CvarDependency> dependencies; 
    ... 
} 
+0

事實上,我必須做一些操縱。對於int,bool和float,管理defaultValue,lowerBound,upperBound很容易,但對於Strings而言不是這樣! – Otacon 2012-02-14 12:02:29

0

勝於讓翻譯提取物和價值觀直接操作,或許會更好地採取不同的方法和定義操作爲這樣的方法:

abstract class Var 
{ 
    ... 
    public Var add(Var var); // corresponds to var + otherVar; in script 
    public Var subtract(Var var); // corresponds to var - otherVar; in script 
    public Var unarySubtract(); // corresponds to -var; in script 
    ... 
} 

這樣你就可以通過調用這些方法評估腳本表達式,你的類可以覆蓋和過載像這樣的例子:

public class IntVar extends Var 
{ 
    ... 
    public IntVar add(IntVar var) 
    { 
     return new IntVar(value + var.value); // add another int 
    } 
    public FloatVar add(FloatVar var) 
    { 
     return new FloatVar(value + var.value); // add another float (and cast result to float? up to you whether you want to do this...) 
    } 
    public StringVar add(StringVar var) 
    { 
     return new StringVar("" + value + var.value); // add a string, and cast to string (for string concatenation) 
    } 
    public Var add(Var var) 
    { 
     throw new OperationNotSupportedException(); // no other types can be added to an IntValue so throw an exception 
    } 
    public Var subtract(Var var) {...} 
    public IntVar unarySubtract() 
    { 
     return new IntVar(-value); 
    } 
    ... 
} 

通過這種方式,您可以實現並評估對它們的操作,無論您希望如何直接在解釋器中直接處理值。

另一個好處是使用這種方法,如果用戶試圖運行一個錯誤的腳本(例如試圖向一個IntVar添加一個BoolVar),那麼將在解釋器中拋出一個異常。

也許你甚至可以有操作的缺省實現在抽象類瓦爾僅僅是這樣的:與操作的安全用途

public Var add(Var var) 
{ 
    throw new OperationNotSupportedException(); // no other types can be added to an IntValue so throw an exception 
} 

而且只覆蓋/超載。

當你在這裏說'讀取內容'時,大概一個類型的實例的內容至少需要在某個時刻以統一的方式處理,如果這只是輸出,那麼爲什麼不只是有一個抽象的'toString()'方法?如果出於其他目的而不是輸出,那麼你有什麼目的不能僅僅擁有其他一些toX()方法並以相同的方式處理每個類型實例呢?

我意識到這並不直接回答你的問題,而是建議一種不同的方法,希望完全避免這個問題,這可能完全沒有幫助,因爲我可能已經對你想要實現的目標做出一些愚蠢的假設。/o更多地看到了問題的背景,但我希望它仍然有幫助。

如果這沒有幫助,那麼請提供一些更多信息,我會盡力幫助更多,因爲它是我不能推薦繼續使用目前的方法,但我不確定除此之外還有什麼建議。

編輯:等等,我的壞,我沒有正確地閱讀這個問題。這不是一個解釋器,而是一個生成器。什麼樣的發電機?什麼語言的腳本生成器?那麼,這些可能不是重要的問題,但現在我已經重讀了這個問題,我意識到我並不真正瞭解你需要達到什麼。

我仍然認爲封裝是比訪問者模式更好的選擇,一般來說:)。當然,除非有什麼理由需要添加行爲來對任何變量進行操作,否則行爲無法通過由Var提供的接口附加到每個變量的行爲來構建......可能會發生什麼行爲這是?對於輸出,你肯定需要每個變量都可以通用的格式來讀取,爲什麼不只是toString(),toSomething(),toAnotherThing()等。

0

我的建議是使用Visitor模式。該算法將被放置在Visitor而不是對象Var(和子類)中。

public class Var { 

    public void accept(VarVisitor visitor) { 
     visitor.visit(this); 
    } 
} 

遊客

public interface VarVisitor { 
    public void visit(FloatVar var); 
    public void visit(IntVar var); 
    public void visit(StringVar var); 
    public void visit(BoolVar var); 

    //...etc. 
    public Object getValue(); 
} 

VisitorImpl

public class VarVisitorImpl implements VarVisitor { 
    private Object value; 

    @Override 
    public Object getValue() { 
     return value; 
    } 

    @Override 
    public void visit(FloatVar var) { 

    } 

    @Override 
    public void visit(IntVar var) { 

    } 

    @Override 
    public void visit(StringVar var) { 

    } 

    @Override 
    public void visit(BoolVar var) { 

    } 
} 

我希望這給你你想要達到什麼樣的一個想法。