views:

131

answers:

3

In a project at work we have a certain value type class in our domain model that includes a very large number of attributes...

public class BigValueType {
    private Foo foo;
    private Bar bar;
    private Baz baz;

    //...
}

We've realized that we would like to "focus" this into a number of different, somewhat more specialized classes that only have some subset of this class's attributes. I think we would like to have something like different "views" of this data.

public class SpecializationA {
    private Foo foo;
    private Baz baz;
    //...
}

public class SpecializationB {
    private Bar bar;
    private Baz baz;
    //...
}

private class SpecializationC {
    private Foo foo;
    private Bar bar;
    //...
}

However, this domain model is intended to be rather general, and not specific to this project. It will have project-specific extensions added to it during future projects, but the common domain model will be kept separate from these extensions. If we simply define a bunch of classes now, it's likely that other projects using the domain model will just have to write their own slightly different ones later. (We can't easily predict what views of this data will be useful.)

I think what we should do is write project-specific Adapters for this big class that present the different views of the data. This way, future users of the domain don't have to touch anything in the "common" domain model to define new views of this information.

public class AdapterA {
    private BigValueType wrapped;
    //...

    public ViewA(BigValueType wrapped) {
     //...
    }

    public Foo getFoo() {
     return wrapped.getFoo();
    }

    //...
}

This makes more sense to me than normal inheritance because our top-level class/interface would have almost nothing in it.

Any feedback on this approach?

A: 

well.. seems fine to me. I think your solution using composition is far better than using inheritance, it will affect your model big time and generate lots of low cohesive classes.

Mauricio
+1  A: 

Firstly, it is important to understand the problem you would want to solve. Having a class with a large number of attributes is not necessarily bad and if you want to do the refactoring only to conform to 'good' design principles, i would reconsider the decision.

Having said that, this is a fairly common design in the world of SOA. You have a large service which takes a complex message with fairly large number of attributes as the request. This service is then 'adapted' to cater to clients with different needs. So, your design should work well. Of course, it presupposes that you already know all the possible 'views' or you would have to write new adapters for new clients.

This 'adaptation' can be performed at two levels - the user interface level (which is essentially your design - to adapt the class) or at a lower level, such as at the database level, and this, in turn modifies your main class too. This would depend on your application, the users of your framework and so on.

An alternate approach to consider could also be the REST way of doing this - expose the data (Foo, Baz, etc) , albeit from the main class, and let the clients do their own processing of the data with the main class essentially providing CRUD features on this data. Then your class behaves more like a structure with no real business logic.

Any of these three approaches should be okay, IMHO.

Anirudh
A: 

I've found that the goal of sharing code across multiple projects is harder than it sounds. As least, it's hard to get it right! This is for exactly the reasons you discuss around not knowing exactly what features you might require in some new project. The trouble is that the adapter problem is not going to solve this for you (if the underlying objects don't support the required feature-set, that is).

I would suggest that you use interfaces for your separate projects but that you code the implementations separately. If you find yourself writing exactly the same code 3 times then pull this out into a common library. Try and keep your library as lightweight as possible.

Managing multiple dependencies can be expensive later on, when you find you need to add features - possibly conflicting ones - and you have the complication of affecting lots of apps.

oxbow_lakes