How much business logic should Value objects conta

2019-03-12 23:46发布

问题:

One mentor I respect suggests that a simple bean is a waste of time - that value objects 'MUST' contain some business logic to be useful.

Another says such code is difficult to maintain and that all business logic must be externalized.

I realize this question is subjective. Asking anyway - want to know answers from more perspectives.

回答1:

You should better call them Transfer Objects or Data transfer objects (DTO).

Earlier this same j2ee pattern was called 'Value object' but they changed the name because it was confused with this

http://dddcommunity.org/discussion/messageboardarchive/ValueObjects.html

To answer your question, I would only put minimal logic to my DTOs, logic that is required for display reasons.

Even better, if we are talking about a database based web application, I would go beyond the core j2ee patterns and use Hibernate or the Java Persistence API to create a domain model that supports lazy loading of relations and use this in the view.

See the Open session in view.

In this way, you don't have to program a set of DTOs and you have all the business logic available to use in your views/controllers etc.



回答2:

The idea of putting data and business logic together is to promote encapsulation, and to expose as little internal state as possible to other objects. That way, clients can rely on an interface rather than on an implementation. See the "Tell, Don't Ask" principle and the Law of Demeter. Encapsulation makes it easier to understand the states data can be in, easier to read code, easier to decouple classes and generally easier to unit test.

Externalising business logic (generally into "Service" or "Manager" classes) makes questions like "where is this data used?" and "What states can it be in?" a lot more difficult to answer. It's also a procedural way of thinking, wrapped up in an object. This can lead to an anemic domain model.

Externalising behaviour isn't always bad. For example, a service layer might orchestrate domain objects, but without taking over their state-manipulating responsibilities. Or, when you are mostly doing reads/writes to a DB that map nicely to input forms, maybe you don't need a domain model - or the painful object/relational mapping overhead it entails - at all.

Transfer Objects often serve to decouple architectural layers from each other (or from an external system) by providing the minimum state information the calling layer needs, without exposing any business logic.

This can be useful, for example when preparing information for the view: just give the view the information it needs, and nothing else, so that it can concentrate on how to display the information, rather than what information to display. For example, the TO might be an aggregation of several sources of data.

One advantage is that your views and your domain objects are decoupled. Using your domain objects in JSPs can make your domain harder to refactor and promotes the indiscriminate use of getters and setters (hence breaking encapsulation).

However, there's also an overhead associated with having a lot of Transfer Objects and often a lot of duplication, too. Some projects I've been on end up with TO's that basically mirror other domain objects (which I consider an anti-pattern).



回答3:

It depends.

oops, did I just blurt out a cliche?

The basic question to ask for designing an object is: will the logic governing the object's data be different or the same when used/consumed by other objects?

If different areas of usage call for different logic, externalise it. If it is the same no matter where the object travels to, place it together with the class.



回答4:

My personal preference is to put all business logic in the domain model itself, that is in the "true" domain objects. So when Data Transfer Objects are created they are mostly just a (immutable) state representation of domain objects and hence contain no business logic. They can contain methods for cloning and comparing though, but the meat of the business logic code stays in the domain objects.



回答5:

What Korros said.

Value Object := A small simple object, like money or a date range, whose equality isn't based on identity.

DTO := An object that carries data between processes in order to reduce the number of method calls.

These are the defintions proposed by Martin Fowler and I'd like to popularize them.



回答6:

I agree with Panagiotis: the open session in view pattern is much better than using DTOs. Put otherwise, I've found that an application is much much simpler if you traffic in your domain objects(or some composite thereof) from your view layer all the way down.

That said, it's hard to pull off, because you will need to make your HttpSession coincident with your persistence layer's unit of work. Then you will need to ensure that all database modifications (i.e. create, updates and deletes) are intentional. In other words, you do not want it be the case that the view layer has a domain object, a field gets modified and the modification gets persisted without the application code intentionally saving the change. Another problem that is important to deal with is to ensure that your transactional semantics are satisfactory. Usually fetching and modifying one domain object will take place in one transactional context and it's not difficult to make your ORM layer require a new transaction. What is challenging is is a nested transaction, where you want to include a second transactional context within the first one opened.

If you don't mind investigating how a non-Java API handles these problems, it's worth looking at Rails' Active Record, which allows Ruby server pages to work directly with the domain model and traverse its associations.