Pergunta

I think this is a common design problem, but I keep scratching my head every time I face it.

On one side, we have our API which sends or receives simple structures aimed to be consumed by web apps, mobile etc. We could potentially have multiple APIs aimed for different devices. On the other side we have our internal domain model which may or may not match the data store entities.

Let assume the following POJOs to assist the discussion.

@POST
public addBlogPost(BlogPostApi blogPost) { ... }

// api model
public class BlogPostApi {
  ...
}

// domain model
public class BlogPost {
  ...
}

// db model
public class BlogPostEntity {
  ...
}

First, we could use the same model in all three layers. While that could be a solution for very simple services, it's usually not a good idea since all the layers are implicitly coupled. So, I'll assume we want to use a different model object per 'layer'.

One approach I've seen widely used is to create adapters between layers. While that solves the problem, it creates an explosion of classes you need to maintain. In the (common) case when you add a new field to the data store which needs to get exposed on the UI as well, 3 POJOs + 2 adapters need to be changed. There's always the risk of forgetting to change one of those. This process could be automated slightly, with the use of an object mapper library.

Another approach I've heard is the use of interfaces. Two or more classes implement the same interface which exposes the get/set methods for 'common' fields. This removes the risk of forgetting to change something, but it creates coupling. Also, I find this use of interfaces wrong, since interfaces should expose functionality.

I'm leaning towards the object mappers. Does anyone know of a olution for this problem?

Foi útil?

Solução

I think adapters is the right approach.

it creates an explosion of classes you need to maintain. In the (common) case when you add a new field to the data store which needs to get exposed on the UI as well, 3 POJOs + 2 adapters need to be changed

That's the effect of having a loosely-coupled system, but you're only describing the negative effect of the loose coupling. What happens when you want to add a new field to the data store, but you don't want to expose it on the UI? This design will allow you to support this use case. It also supports cases where you want to store things in the database differently than how they look in the domain model which is a fairly common need. For example, I like to have auto-increment numeric ids on all my database tables for foreign keys and join efficiency, but often the domain model may use some other unique field as its identifying field. With the three model approach I don't have to leak the db id to the domain layer.

Outras dicas

Although the OP is referencing Java, I have a C#-based solution that directly applies. You can use the MVC design pattern to completely decouple your UI, BL, and DAL through interfaces and adapters. I have implemented such a solution with the GPS.SimpleMVC package on GitHub. You can read more about it at http://simplemvc.gatewayprogramming.school.

Now, the meat and potatoes comes from using Interfaces to define the views and the data/actions associated with those views. You can choose to couple the views to Models, or decouple the views through logic in the controllers. The controllers accept instances of views as input and register to the events exposed by those views. For example, if you need to tell the controller to load some data, you use a delegate (event) to signal to the controller to do some work. The controller then is responsible for creating the Models. The Models are responsible for exposing a DAL via a common interface. Inside the POCO Models are code to load an adapter based on configuration using Dependency Injection. The adapter has the code to perform the data access.

This completely decouples the three layers from the implementation details of each other. The strong coherence comes from the appropriate use of interfaces.

Licenciado em: CC-BY-SA com atribuição
scroll top