5
class A{
    private List<T> list;

    public int getListSize(){
        return list.size();
    }
}

class B{
    private A objectA;

    public int getSizeOfListInA{
        return objectA.getListSize();
    }


}

class C{
    B objectB;
    // here I need to know the size of the list 
}

I'm oversimplifying here, but I was wondering if this is the right way to write proper code - suppose class C needs to know the size of the list. If there was another class D holding object of class C in it, and D wanted to know the size of the list from A, I'd need another getSizeOfTheList method in class C. So it's a lot of code duplication - three methods that generally do the same thing, simply because a class that is level up wants to know its internal stuff. Of course it would be best if C didn't have to know the list size, but sometimes it makes sense.

Edit:

If A was immutable class, then maybe it would better to have getObjectA instead in class B? Suppose I want to make available all objectA methods to the clients of class B - by including getObjectA method I don't need to rewrite each of them in B. The client would simply first call getObjectA and then call its method.

The question is obviously whether I really want clients to access all methods of A. And it would be harder for clients of B to use my API. So either me or my clients will have easier life.

1 Answer 1

8

You're right to be unsure about this, since sometimes this is perfectly fine and sometimes it indicates a massive design fail.

The key thing to look for is whether this "sameness" is just an accidental property of the implementations, or a necessity imposed by the (implicit) method contracts. The former is okay, while the latter indicates serious redundancy.

For example, here's a case where it's probably acceptable:

// this class is part of the database implementation used for SELECT queries
class ReadOnlyDatabaseRowImplList implements DatabaseRowImplList {
    private List<DatabaseRowImpl> rows;
    public int getRowCount() { return rows.size(); }
    // other methods
}

// this class is what the database returns to the microservice for any type of query
class QueryResult {
    private DatabaseRowImplList rows;
    public int numRowsAffected() { return rows.size(); }
    // other methods
}

// this class is what the microservice returns to the client
class CompanyEarningsHistory {
    private QueryResult earnings;
    public int yearsWithHistoryAvailable() { return earnings.numRowsAffected(); }
    // other methods
}

The three methods happen to have (nearly) identical implementations, but the semantics are different at each level, and the user of each method neither knows nor cares if the implementation is "just a passthrough" or not. It's entirely possible one of these methods might change in the future to have more interesting logic in it while maintaining their implicit contracts.

But if you find yourself writing something like this:

class FooWrapper {
    private Foo foo;

    // returns the current value of the bar member on this class' internal foo object
    public SomeType getFooDotBar() {
        return foo.bar;
    }
}

Then it's very likely that you've made a mistake somewhere. Ideally, see if you can find out why FooWrapper users think they need getFooDotBar() and come up with a way to incorporate that feature/workaround into the "clean part" of your API. In some rare cases your users really will need direct access to one of the objects you're wrapping, in which case you should either expose the whole Foo object directly, or perhaps a read-only wrapper thereof (see methods like Collections.unmodifiableList()).

4
  • Very nice, clear example.
    – biziclop
    Apr 5, 2016 at 12:27
  • Please check my additional question in edit. Thanks. Apr 9, 2016 at 17:12
  • @user4205580 What you're describing in your edit sounds potentially reasonable, though again it's impossible to say with any confidence without knowing far more about these hypothetical objects. Also, if you want to ask another question, it's best to actually post a brand new question rather than making edits here which might invalidate the existing answer(s).
    – Ixrec
    Apr 9, 2016 at 17:31
  • @Ixrec IMO it's still the same question, I just wasn't precise enough. Apr 9, 2016 at 18:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.