2009-12-03 30 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");