2013-10-11 76 views
7

這是一個關於我不確定如何在Java中解決的問題。我想根據三種類型的數據(URI,字符串或文字)製作三重語句,每種類型的編碼方式都不相同。我已經編寫了接受這些類型的編碼方法。在Java中接受不同類型的參數

public static String makeStatement(URI subject, URI predicate, String object) { 
    return " " + encode(subject) + " " + encode(predicate) + " " + encode(object) + ".\n"; 
} 

public static String makeStatement(String subject, URI predicate, String object) { 
    return " " + encode(subject) + " " + encode(predicate) + " " + encode(object) + ".\n"; 
} 

public static String makeStatement(URI subject, URI predicate, Literal object) { 
    return " " + encode(subject) + " " + encode(predicate) + " " + encode(object) + ".\n"; 
} 

private static String encode(String binding) { 
    return "?" + binding; 
} 

private static String encode(URI uri) { 
    return "<" + uri.stringValue() + ">"; 
} 

private static String encode(Literal literal) { 
    return "\"" + literal.stringValue() + "\"" + literal.getDatatype(); 
} 

但我能接受這些類型的,這需要9個makeStatement功能,基本上做同樣的事情的任意組合,這似乎像一個壞主意,特別是因爲有可能我想補充另一稍後鍵入。

通常我會回答這樣一個問題,建議創建一個superClass,但我不能編輯String,URI和Literal。另一種選擇是定義

public static String makeStatement(Object subject, Object predicate, Object object) { 
    String encodedSubject = "", encodedPredicate = "", encodedObject = ""; 
    if (subject.getClass().equals(URI.class)) { 
     encodedSubject = encode((URI) subject); 
} 
    return " " + encode(encodedSubject) + " " + encode(encodedPredicate) + " " + encode(encodedObject) + ".\n"; 
} 

然後檢查類各的說法,但我認爲這不是很優雅。 另一個建議是定義諸如makeStatement(URI subjectURI,String subjectString,Literal subjectLiteral,URI predicateURI ..等)之類的東西,然後檢查哪些參數爲null並從那裏開始,但這意味着當我打電話時輸入很多空值功能。 第三個選項是https://stackoverflow.com/a/12436592/1014666,但這又需要在調用makeStatement函數時進行一些額外的輸入。

有什麼建議嗎?

+0

一個同事面對類似的問題,他回來了,他寫了一個Python腳本,將所有9個組合寫成.java文件中的文本 – mbatchkarov

+0

不錯,但不是很優雅:) – Rhand

+0

編寫一個通用方法接受所有對象作爲對象並在裏面做檢查的實例,並根據需要執行操作。它可能會給你另一種觀點。 – Arung

回答

3

您可以使用生成器模式:

public class StatementMaker { 
    private static String encode(String binding) { 
     return "?" + binding; 
    } 

    private static String encode(URI uri) { 
     return "<" + uri.stringValue() + ">"; 
    } 

    private static String encode(Literal literal) { 
     return "\"" + literal.stringValue() + "\"" + literal.getDatatype(); 
    } 

    public static Statement from(String b) { 
     return new Statement(encode(b)); 
    } 

    public static Statement from(URI b) { 
     return new Statement(encode(b)); 
    } 

    public static Statement from(Literal b) { 
     return new Statement(encode(b)); 
    } 

    public static class Statement { 

     private StringBuilder buf; 
     private Statement(String s) { 
      buf = new StringBuilder(" "); 
      buf.append(s); 
     } 

     public Statement with(String s) { 
      buf.append(" ").append(encode(b)); 
      return this; 
     } 

     public Statement with(URI s) { 
      buf.append(" ").append(encode(b)); 
      return this; 
     } 

     public Statement with(Literal s) { 
      buf.append(" ").append(encode(b)); 
      return this; 
     } 

     public String toString() { 
      return buf.toString() + ".\n"; 
     } 

    } 
} 

現在,您可以構建語句例如:

StatementMaker.from(subject).with(predicate).with(object).toString()

在需要的報表,可以進一步縮短代碼靜態導入代碼:

import static my.package.StatementMaker.from;

然後語句簡化爲:

from(subject).with(predicate).with(object).toString()

你可以添加3個更多的方法到內部類:

public static class Statement { 

    private StringBuilder buf; 
    private Statement(String s) { 
     buf = new StringBuilder(" "); 
     buf.append(s); 
    } 

    public Statement with(String s) { 
     buf.append(" ").append(encode(b)); 
     return this; 
    } 

    public Statement with(URI s) { 
     buf.append(" ").append(encode(b)); 
     return this; 
    } 

    public Statement with(Literal s) { 
     buf.append(" ").append(encode(b)); 
     return this; 
    } 

    public String and(String s) { 
     buf.append(" ").append(encode(b)); 
     return buf.toString() + ".\n"; 
    } 

    public String and(URI s) { 
     buf.append(" ").append(encode(b)); 
     return buf.toString() + ".\n"; 
    } 

    public String and(Literal s) { 
     buf.append(" ").append(encode(b)); 
     return buf.toString() + ".\n"; 
    } 


    public String toString() { 
     return buf.toString() + ".\n"; 
    } 

} 

然後你可以使用避免toString()調用是這樣的:

String statement = from(subject).with(predicate).and(object);

+0

我喜歡這個答案,因爲makeStatement變得更清晰,但是,toString在每一行的結尾都不太好。 – Rhand

+0

在這之後你甚至不需要makeStatement方法。 如果你想避免可以向Statement內部類添加3個方法。我會添加他們來回答。 –

+0

添加了避免toString()調用的方法。 –

2

如果只有少數選項,則方法重載很有效。你在這裏有點迷戀。如果有一種簡單的方法從一種轉換爲另一種,則不需要具備所有選項。

因此,忘記擁有每一種可能的選擇,並提供最常用的選擇。

+0

不幸的是,沒有簡單的方法可以從一個轉換到另一個。對於我目前正在使用的軟件,我發現自己正在編寫其中80%的行可能包含makeStatement調用的函數。 – Rhand

+0

沒有簡單的方法來從URI轉換爲字符串,反之亦然? – Kayaman

+0

當然,有一種簡單的方法可以將URI從一個字符串轉換爲一個字符串,但在我的上下文中,我想用<>包裝一個URI,並將一個?在字符串之前。 – Rhand

1

通常情況下,我會回答這樣的問題,建議創建一個超類,但我不能 編輯字符串,URI和文字。另一種選擇將是定義

我會去一個類似的方法,但不是提取超類,正如你所說,你不能這樣做,你可以創建一個包裝。

public class LiteralWrapper { 
    private String string = null; 
    private URI uri = null; 
    private Literal literal = null; 

    public LiteralWrapper(String sting) { 
     this.string = string; 
    } 

    public LiteralWrapper(URI uri) { 
     this.uri = uri; 
    } 

    public LiteralWrapper(Literal literal) { 
     this.literal = literal; 
    } 

    // Note that this class is immutable, 
    // so you know you cannot have more than one non-null member. 
    // Probably not a bad idea to add some getters, though. 


    /* The encode functions from your original question */ 

    private static String encode(String binding) { 
     return "?" + binding; 
    } 

    private static String encode(URI uri) { 
     return "<" + uri.stringValue() + ">"; 
    } 

    private static String encode(Literal literal) { 
     return "\"" + literal.stringValue() + "\"" + literal.getDatatype(); 
    } 

    @Override 
    public String toString() { 
     if (literal != literal) { 
      return encode(literal); 
     } 
     if (uri != null) { 
      return encode(uri); 
     } 
     return encode(string); 
    } 
} 

現在你makeStatement代碼變得微不足道:

public static String makeStatement(LiteralWrapper subject, LiteralWrapper predicate, LiteralWrapper object) { 
    return " " + subject + " " + predicate + " " + object + ".\n"; 
} 

編輯:
按下面的評論,這使得調用makeStatement有點討厭。您無需執行makeStatement(myString, myUri, myLiteral),而是強制撥打makeStatement(new LiteralWrapper(myString), new LiteralWrapper(myUri), new LiteralWrapper(myLiteral))。 這個問題不能用給定的解決方案完全避免,但可以通過在工廠方法的形式引入一些語法糖來緩解:

public static LiteralWrapper wrap(String string) { 
    return new LiteralWrapper(string); 
} 

public static LiteralWrapper wrap(URI uri) { 
    return new LiteralWrapper(uri); 
} 

public static LiteralWrapper wrap(Literal literal) { 
    return new LiteralWrapper(literal); 
} 

現在,你需要的地方,你可以staticly導入這些包裝使用makeStatement

import static org.some.package.LiteralWrapper.wrap; 
/* other imports*/ 

public class MyClass { 
    public void someFunction() { 
     /* some business logic */ 

     makeStatemet(wrap(myString), wrap(myURI), wrap(myLiteral)); 
    } 
} 
+0

感謝您的回答,這與我在問題中提到的答案類似。到目前爲止,這是最優雅的選擇,但是這會將我的makeStatement(「subject」,「predicate」,「object」)轉換爲makeStatement(新的StatementWrapper(「subject」),新的StatementWrapper(「predicate」),StatementWrapper目的」));這並不能真正提高可讀性。 – Rhand

+0

@Rhand我同意這有點妨礙可讀性。請參閱我的編輯以獲得解決上述問題的方法。恕我直言,解決方案的結果是非常可讀的代碼,但這一切都在旁觀者的眼中。 – Mureinik

+0

我喜歡包裝功能(這是由其他答案擴展) – Rhand

1
public static String makeStatement(Object subject, Object predicate, Object object) { 
    return " " + encode(subject) + " " + encode(predicate) + " " + encode(object) + ".\n"; 
} 

private static String encode(Object obj) { 
    String encodedOj =""; 
    if (obj.getClass().equals(URI.class)) { 
     encodedOj = encode((URI) obj); 
    }else if(obj.getClass().equals(Literal.class)){ 
     encodedOj = encode((Literal) obj); 
    }else if(obj.getClass().equals(String.class)){ 
     encodedOj = encode((String) obj); 
    } 
    return encodedOj; 
} 

private static String encode(String binding) { 
    return "?" + binding; 
} 

private static String encode(URI uri) { 
    return "<" + uri.stringValue() + ">"; 
} 

private static String encode(Literal literal) { 
    return "\"" + literal.stringValue() + "\"" + literal.getDatatype(); 
} 
+0

你知道是否有性能影響檢查每個Object obj的類嗎?與U Mad的答案相比,這似乎是主要區別(而makeStatement函數則非常不同)。 – Rhand

+0

感謝您的回答,這將工作,但我更喜歡U瘋狂的回答 – Rhand

+1

問題是,任何對象都可以傳入。這本身就是代碼嗅覺,但更糟的是,如果'makeStatement'被調用的東西是不是'URI','Literal'或者'String','encode(Object)'方法會自動失敗並返回一個空字符串。你應該至少添加'else拋出新的IllegalArgumentException',如果塊。 –

0

您可以創建有趣和易於使用的包裝用靜態工廠方法(見有效的Java,項目1)和匿名類(充當閉包等)。

方法如下:

public class Item { 

    private static interface Methods { 
     public String encode(); 
    } 

    private final Methods methods; 

    private Item(Methods methods) { 
     this.methods = methods; 
    } 

    public static Item of(final String binding) { 
     return new Item(new Methods() { 
      @Override 
      public String encode() { 
       return "?" + binding; 
      } 
     }); 
    } 

    public static Item of(final URI uri) { 
     return new Item(new Methods() { 
      @Override 
      public String encode() { 
       return "<" + uri.stringValue() + ">"; 
      } 
     }); 
    } 

    public static Item of(final Literal literal) { 
     return new Item(new Methods() { 
      @Override 
      public String encode() { 
       return "\"" + literal.stringValue() + "\"" + literal.getDatatype(); 
      } 
     }); 
    } 

    public String encode() { 
     return methods.encode(); 
    } 
} 

這真的很容易用這種方法添加新的支持的類型(這是你的需求之一):只要創建新的靜態工廠方法接受此類型:Item.of(NewType val)

所以,你將有一個方法:

public static String makeStatement(Item subject, Item predicate, Item object) { 
    return subject.encode() + " " + predicate.encode() + " " + object.encode(); 
} 

,並調用它像:

makeStatement(Item.of(subject), Item.of(predicate), Item.of(object)); 

添加新的方法也很簡單(但它會有點像修改,而不是延長) - 只需將它們添加到Methods接口並在所有支持類型的閉包中實現。無論如何,編譯器會讓你。

+0

感謝您的回答,這是可行的,但我更喜歡U Mad的回答 – Rhand

+1

事實上,這對您的特定問題更好。我試圖解決更通用的問題(接受不同類型的論據)。 – siledh

相關問題