So far I've been building applications abstracting data entity operations behind the use of Repositories
. Each of them would encapsulate the domain that corresponds to their defined entity. For instance: UserRepository
would encapsulate domain logic regarding the User
entity, such as changePassword(old,new)
, createAccount(email,password
, retrieveAllFriendsForUser(id)
and such.
But there are cases where you need multiple resources to interact and abstracting that logic in a repository from another entity feels smelly. For example: buying an Item
would require you to create a Quotation
, create a Payment
, reducing the ItemQuantity
from the Inventory
and such; handling that operation in the ItemRepository
would mean it's implementation would depend on QuotationRepository
, PaymentRepository
, etc...
I've read before about the Business Facade and the Unit of Work patterns, but having just read them again they seem not to be aimed at this specific multiple resource interaction issue, but rather aimed at simplified access to chunks of code and handling atomic operations, respectively.
What's a design pattern for handling multiple resource interaction and if possible a quick example code that complements it.
2 Answers 2
What you're describing is business logic. Purchasing an Item is a business transaction. This belongs in the Service layer.
Remember that the Repository layer acts as a facade for persistence, and exists to abstract the underlying details of your persistence mechanism from the rest of your application.
The Service layer, by contrast, exposes business logic that uses your repositories. The service layer should coordinate the different transactions from the different repositories
I think you are confusing a few different ideas here.
The repository is usually used an abstraction between the consuming code and the persistence component. Typical methods on a UserRepository would be
interface UserRepository {
void save(User user);
User getById(UserId id);
}
Operations to change the User would normally be implemented on the User itself
interface User {
void changePassword(String newPassword);
}
Objects that are used to coordinate concerns distributed among multiple components are usually constructed with references to the components. You'll often find that a Factory is used to create the objects; including factories that call into other factories to get the individual parts.
When the specification of the object to be created is particularly complicated, you are likely to see a Builder enter the picture, as a mechanism for collecting the various arguments that are going to be needed to create the object graph.
Things get more complicated when you are dealing with objects that are stored in separate repositories. What you are likely to see in this case are atomic operations on the objects, which send asynchronous messages to each other to communicate changes.
For instance: a customer places an order for some product. The new state of the order is saved in the order repository. A process manager observes the new order, and dispatches an asynchronous message to the warehouse component to ship the order. The appropriate warehouse is loaded from the warehouse repository to update the inventory in stock, etc, and save that information off. In removing the inventory from the stock, the warehouse observes that the available stock has dropped below the reserve limit, so another asynchronous message is dispatched to report this. Yet another component picks up this message, and starts the work of ordering more stock from the supplier, etc.
PurchaseRepository
orPurchaseService