2009-12-03 37 views
3

我有一個簡單的問題,嘗試使用Appengine保持DRY。幫助創建泛型類以避免代碼複製

除了作爲參數發送的對象外,下面的2個函數是相同的。實際上我有15個這樣的功能。我試圖找到一種方法來創建一個超類或通用來實現這一點。

public void deleteRecord(Person s) { 

    PersistenceManager pm = PMF.get().getPersistenceManager(); 
    try { 
     Person p = pm.getObjectById(Person.class, s.getId()); 
     pm.deletePersistent(p); 
    } finally { 
     pm.close(); 
    } 
} 

public void deleteRecord(Product s) { 

    PersistenceManager pm = PMF.get().getPersistenceManager(); 
    try { 
     Product p = pm.getObjectById(Product.class, s.getId()); 
     pm.deletePersistent(p); 
    } finally { 
     pm.close(); 
    } 
} 

遺憾的是,似乎我不能使用泛型,因爲仿製藥不支持T.class。

任何好的建議如何做到這一點w/o複製?

謝謝。 丹尼爾

+0

你不能修改你的方法接受一個類,而不是一個對象? – JRL

+1

做這些方法是否需要在同一個類中,或者像它自己的類中的每個方法一樣? – meriton

回答

2

DRY是一個很好的原則。所以KISS是;-)

public void deleteRecord(Class classOfProduct, Object id) { 

    PersistenceManager pm = PMF.get().getPersistenceManager(); 
    try { 
      Object p = pm.getObjectById(classOfProduct, id); 
      pm.deletePersistent(p); 
    } finally { 
      pm.close(); 
    } 
} 

這將與被調用,例如:

theObject.deleteRecord(Person.class, s.getId()); 
theObject.deleteRecord(Product.class, s.getId()); 

因爲這是一個無效的方法,以及PersistenceManager的沒有出現與泛型類型的工作,我會建議避免使用泛型。這種方法(如果適用的話)有額外的好處,您不需要修改產品,人員等的類型層次結構。

缺點是,如果從多個地方調用此方法,可能會有很多地方改變簽名 - 但編譯器很容易找出需要多長時間。

+0

唯一的問題是你的代碼沒有編譯時間限制某人試圖刪除一個無效類型,即theObject.deleteRecord(Integer.class,s.getId())會編譯,但在運行時失敗。 – pstanton

+0

即使這樣,我可能不會轉向泛型,我很可能會使用枚舉類型給出的編譯時間約束。因此,枚舉將包含可以提供所需15個左右類的成員。你認爲泛型是比這更好的選擇嗎? – Grundlefleck

+0

「PersistenceManager似乎不能與泛型類型一起工作」我不認爲Apache(或Oracle)的任何代碼都使用泛型。 Apache的集合可能是個例外。 – Powerlord

4

您不需要仿製藥;使用thing.getClass():

public void deleteRecord(Object thing) { 
    ... 
    Object o = pm.getObjectById(thing.getClass(), s.getId()); 
    ... 
} 

(你應該在那裏以防萬一傳入的參數爲空加空檢查)

[注:我改變了我的答案,我剛剛發佈後,當我意識到你並不需要仿製藥在這裏...]

+4

除了object不提供getId方法,所以你需要聲明爲<?擴展SuperType>,其中SuperType實現或聲明(抽象)getId方法。 – pstanton

+0

您需要一個具有getId()方法的公共超類(或接口)。 – Buhb

+0

@pstanton:你不需要泛型來管理它。 – Buhb

2

最簡單的方法是引入類型作爲參數:

public <T> void deleteRecord(Class<T> type, T s) { 
     PersistenceManager pm = PMF.get().getPersistenceManager(); 
     try { 
       T p = pm.getObjectById(type, s.getId()); 
       pm.deletePersistent(p); 
     } finally { 
       pm.close(); 
     } 
} 

如果你的人員,產品等都是隻有簡單的一個班d沒有子類,您可以使用getClass()而不是像Scott建議的那樣指定明確的參數。

+1

你的意思是在你的例子中使用'Product.class'嗎?你是否不是指參數'type'中的某個東西? – Grundlefleck

+0

我認爲,你想寫'type'而不是'Product.class' ...我是對嗎? –

+0

是的,沒錯。編輯。 – Jorn

1

如果你在DAO中使用這個,我傾向於用這個類來初始化它。所以也許

public class DAO<T> { 

    private Class klass 

    public DAO(Class klass) { 
    this.klass = klass; 
    } 

    public void deleteRecord(T record) { 
    PersistenceManager pm = PMF.get().getPersistenceManager();  
    try {  
     T p = pm.getObjectById(this.klass, record.getId());  
     pm.deletePersistent(p);  
    } finally {  
     pm.close();  
    } 
    } 
} 
4

這可能不是最簡單的做事方式,但我忍不住想從長遠來看最有意義。

創建界面

// This is a terrible name, I know 
public interface Identifier { 
    // Assumes ID was an int 
    public int getId(); 
    // Maybe have setId, too 
} 

而且在每個班,實現該接口及其方法

public class Person implements Identifier { 
    public int getId() { 
     //Implementation details here 
    } 
} 

最後,你的刪除方法:

public void deleteRecord(Identifier s) { 

    PersistenceManager pm = PMF.get().getPersistenceManager(); 
    try { 
     Identifier p = pm.getObjectById(s.getClass(), s.getId()); 
     pm.deletePersistent(p); 
    } finally { 
     pm.close(); 
    } 
} 

注意:我還沒有完全測試過這...具體來說,我還沒有測試pm.deletePersistent(p)wor ks與PersistenceManager

+0

我中途寫了同樣的東西。 – pstanton

+0

@pstanton:我在看到Buhb的回覆之前寫了這個。但是,事實證明,Grundlefleck可能有一個更好的主意。 – Powerlord

+0

不,我個人更喜歡你/我們的方法。編譯時間安全並正確使用繼承=好。 – pstanton

0

您可以使用一個枚舉來掩飾這一點:

class FetchableThing {} 
class Person extends FetchableThing {} 
class Organisation extends FetchableThing {} 

enum DAO<T extends fetchableThing> { 
    Person(Person.class), Organisation(Organisation.class); 

    private Class<T> myClass; 
    private DAO(Class<T> myClass) { this.myClass=myClass;} 

    public delete(String id) { 
     PersistenceManager pm = PMF.get().getPersistenceManager(); 
     try { 
      T p = (T) pm.getObjectById(myClass, id); 
      pm.deletePersistent(p); 
     } finally { 
      pm.close(); 
     } 
    } 
} 

DAO.Person.delete("1234"); 
DAO.Organsation.delete("1234");