Abstract Class with member that is also abstract

I have an abstract class that I use to define some abstract methods that will be shared between the subclasses (This is what I understand to be the correct usage of abstract classes. Since this for a set of classes that are very similar I decided to go with an abstract class rather than an interface.)

public abstract class DomainService<T extends Domain> {

    abstract public void insert(T object) throws ValidationException;

    abstract public void delete(T object) throws EntityNotFoundException;

    abstract public List<T> fetchAll();
}

T is the domain class that is related to and all the domain classes have a common superclass called Domain

public abstract class Domain implements Serializable {

    private static final long serialVersionUID = 8868922239517301371L;

    private static Logger log = LoggerFactory.getLogger(Domain.class);

    public Domain() {
    }

    public List<String> getColumnMembers() {
        Field[] declaredFields = this.getClass().getDeclaredFields();

        List<String> declaredFieldsNames = new ArrayList<String>(declaredFields.length);
        for (Field field : declaredFields) {
            if (Modifier.isStatic(field.getModifiers()) || !field.isAnnotationPresent(Column.class)) {
                continue;
            }
            declaredFieldsNames.add(field.getName());
        }

        return declaredFieldsNames;
    }

    public abstract Object getPrimaryKey();
}

And each Domain has a DomainAccess class that access the tables in the database and all these have a common superclass called DomainAccess for the shared methodds

public abstract class DomainAccess<T extends Domain> {

    protected abstract Logger getLogger();

    protected DatabaseFacade db;

    protected Class<T> domainClass;

    @Inject
    public DomainAccess(DatabaseFacade databaseFacade, Class<T> domainClass) {
        this.db = databaseFacade;
        this.domainClass = domainClass;
    }

    @SuppressWarnings("unchecked")
    public T fetchByPrimaryKey(Object primaryKey) {
        return (T) db.find(domainClass, primaryKey);
    }

    public boolean exists(T object) {
        return fetchByPrimaryKey(object.getPrimaryKey()) == null ? false : true;
    }

    public void save(T object) {
        db.save(object);
    }

    public void merge(T object) {
        db.merge(object);
    }

    public void delete(T object) {
        db.remove(object);
    }

    public void saveOrUpdate(T object) {
        if (exists(object)) {
            merge(object);
        } else {
            save(object);
        }
    }

    public void deleteByPrimaryKey(T object) throws EntityNotFoundException {
        Object primaryKey = object.getPrimaryKey();
        T objectToDelete = fetchByPrimaryKey(primaryKey);

        if (objectToDelete != null) {
            getLogger().debug("There was no entry found with primary key: " + primaryKey);
            throw new EntityNotFoundException("No entry was found with specified primary key [" + primaryKey + "]");
        } else {
            getLogger().debug("Deleting entry with id: " + primaryKey);
            delete(objectToDelete);
        }
    }

    @SuppressWarnings("unchecked")
    public List<T> getResultList(String hql, String... parameters) {
        TypedQuery<T> query = db.createTypedQuery(hql, domainClass);
        for (int i = 0; i < parameters.length; i++) {
            query.setParameter(i + 1, parameters[i]);
        }
        return query.getResultList();

    }

    @SuppressWarnings("unchecked")
    public T getSingleResult(String hql, String... parameters) {
        TypedQuery<T> query = db.createTypedQuery(hql, domainClass);
        for (int i = 1; i <= parameters.length; i++) {
            query.setParameter(i, parameters[i - 1]);
        }

        return query.getSingleResult();
    }
}

My question other than any remarks you may have on what you see here, is the following:

The delete method in the DomainService is the same for each subclass, i.e.

UserService:
    @Transactional
    @Override
    public void delete(User user) throws EntityNotFoundException {
        userAccess.deleteByPrimaryKey(user);
    }
DepartmentService:
    @Transactional
    @Override
    public void delete(Department department) throws EntityNotFoundException {
        departmentAccess.deleteByPrimaryKey(department);
    }

So I was thinking of moving it to the abstract parent class. But to do that I would have to define the DomainAccess there, something like this at a guess

public abstract class DomainService<T extends Domain> {

    protected DomainAccess<T> domainAccess;

    protected DomainService(DomainAccess<T> domainAccess) {
        this.domainAccess = domainAccess;
    }

    abstract public void insert(T object) throws ValidationException;

    public void delete(T object) throws ValidationException {
        domainAccess.deleteByPrimaryKey(user);
    }       
    abstract public List<T> fetchAll();
}

with the DomainService passed in the subclass constructor

@Inject
public UserService(UserAccess userAccess) {
    super(userAccess);
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    this.validator = factory.getValidator();
}

but if I do that then in the subclasses, let’s say UserService a method I had

@Override
public List<User> fetchAll() {
    return userAccess.fetchAllUsers();
}

would have to become like this

@Override
public List<User> fetchAll() {
    return ((UserAccess)domainAccess).fetchAllUsers();
}

and that would have to be done everytime I used a specific method to the subclass.

That seems wrong. Are there any pointers or ways of thinking to how much you can use generics or abstraction?


Source: oop

Leave a Reply