开发者

Help to create a generic class to avoid code duplication

I have a simple problem try to stay DRY using Appengine.

The 2 functions below are identical except for the object sent as parameter. In reality I have 15 functions like this. I am try to find a way to create a super class or a generic to achieve this.

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

and

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

Unfortunately it seems that I cannot use generics since generics don't support T.class.

Any good suggestion how to do this w/o duplicating?

Thank you. Daniel


You don't need generics for this; use thing.getClass():

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

(you should add a null-check in there just in case the parameter passed in was null)

[Note: I changed my answer just after I posted it when I realized you don't need generics here...]


This may not be the easiest way to do things, but I can't help but think it would make the most sense in the long run.

Create an interface

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

And in each of your classes, implement the interface and its method

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

and finally, your delete method:

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

Note: I haven't completely tested this... Specifically, I haven't tested whether pm.deletePersistent(p) works with PersistenceManager.


DRY is a good principle. So is 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();
    }
}

This would be called with, for example:

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

Since this is a void method, and PersistenceManager does not appear to work with generic types, I would advise avoiding using generics. This method, if applicable, has the added bonus that you won't need to modify the type hierarchy of Product, Person, etc.

The downside is that if this method is called from several places, there may be many places to change the signature - but it's easy to let the compiler find out how long it would take.


The easiest way would be to introduce the type as a parameter:

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

If your Persons, Products etc are only simple classes and don't have subclasses, you could use getClass() instead of specifying an explicit parameter, as suggested by Scott.


If you're using this in a DAO, I tend to initialize it with the class. So maybe

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


You can use an enum to conceal this:

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");
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜