> Rich domain models are wrong because the assumption is > placing logic in one place (a domain class) is a good > idea. ... > > Anemic domain models are wrong because they flatten an > architecture into orthogonal layers, requiring developers > to pass tramp parameters to pass an object across multiple > layers. > I think I wasn't clear. Let me try to clarify what I mean, because I wasn't trying to say that DCI promotes anemic domain models. Instead it challenges a basic assumption inherent in the notion of an anemic domain model. The assumption is that an object has a class.
Basically what we've been doing in OO modeling is designing classes whose names often map to the domain. So if there's an "account" in the problem domain, then we might have an Account class in the code. But what behavior do we attach to that class? Well, if the class is anemic, then it is just simple behavior of getting and setting data. The class is "dumb," little more than a glorified data holder. If the class is non-anemic, then it will have more interesting behavior that has something to do with the data. In OO we tend to move the behavior that uses data to the classes that have the data.
OK. So what happens is that if the account concept is involved in 10 use cases of your application, you may end up placing some behavior for each of those use cases into class Account. Deciding what behavior to put in and what to leave out is the designer's challenge.
DCI challenges the assumption that each object has one and only one class. The observation is that objects need different behavior in different contexts. So why not let an object have a different class in each context? The way it shakes out is that you will have an anemic Account class in your design, and different traits that can be mixed into Account to supply just the extra (non-anemic) behavior needed for the use case at hand. And DCI also suggests is that use map these traits to conceptual roles in the user's thinking.
Since you like code, let me show you how this maps to Scala, in which you can model it nicely. You can have a anemic class Account, and then mix in one ore more traits at instantiation time. So in the transfer use case, you might write:
val source = new Account with TransferMoneySource
What the Scala compiler does with this is create an anonymous class (it creates a class and assigns it a name that includes some dollar signs) that extends SavingsAccount and mixes in TransferMoneySourceAccount, then creates an instance of that. On the JVM then, each object does have one and only one class. But the conceptual account object may have many different classes, one of which is the anonymous class created here that is only used in this one use case.