Sample domain service

Let us create a sample domain service based on our table reservation system. As discussed in this chapter, the importance of an efficient domain layer is the key to successful products or services. Projects developed based on the domain layer are more maintainable, highly cohesive, and decoupled. They provide high scalability in terms of business requirement change and have a low impact on the design of other layers.

Domain-driven development is based on domain, hence it is not recommended that you use a top-down approach where the UI would be developed first, followed by the rest of the layers and finally the persistence layer, or a bottom-up approach where the persistence layer like the DB is designed first and then the rest of the layers, with the UI at last.

Having a domain model developed first, using the patterns described in this book, gives clarity to all team members functionality wise and an advantage to the software designer to build a flexible, maintainable and consistent system that helps the organization to launch a world class product with less maintenance costs.

Here, you will create a restaurant service that provides the feature to add and retrieve restaurants. Based on implementation, you can add other functionalities such as finding restaurants based on cuisine or on rating.

Start with the entity. Here, the restaurant is our entity as each restaurant is unique and has an identifier. You can use an interface or set of interfaces to implement the entity in our table reservation system. Ideally, if you go by the interface segregation principle, you will use a set of interfaces rather than a single interface.

For the first interface you could have an abstract class or interface that is required by all the entities. For example if we consider ID and name, attributes would be common for all entities. Therefore, you could use the abstract class Entity as an abstraction of entity in your domain layer:

Based on that you can also have another abstract class that inherits Entity, an abstract class:

Based on the preceding abstractions, we could create the Restaurant entity for restaurant management.

Now since we are developing the table reservation system, Table is another important entity in terms of the domain model. So, if we go by the aggregate pattern, restaurant would work as a root, and table would be internal to the Restaurant entity. Therefore, the Table entity would always be accessible using the Restaurant entity.

You can create the Table entity using the following implementation, and you can add attributes as you wish. For demonstration purpose only, basic attributes are used:

Now, we can implement the aggregator Restaurant shown as follows. Here, only basic attributes are used. You could add as many you want or may add other features also:

Now, we can implement the repository pattern as learned in this chapter. To start with, you will first create the two interfaces Repository and ReadOnlyRepository. ReadOnlyRepository will be used to provide abstraction for read only operations whereas Repository abstraction will be used to perform all types of operations:

Based on this interface, we could create the abstraction of the repository that would do additional operations such as adding, removing, and updating:

Repository abstraction as defined previously could be implemented in a way that suits you to persist your objects. The change in persistence code, that is a part of infrastructure layer, won't impact on your domain layer code as the contract and abstraction are defined by the domain layer. The domain layer uses the abstraction classes and interfaces that remove the use of direct concrete class and provides the loose coupling. For demonstration purpose, we could simple use the map that remains in the memory to persist the objects:

In the same way as the preceding approach, you could divide the abstraction of domain service into two parts: main service abstraction and read only service abstraction:

Now, we could use this ReadOnlyBaseService to create the BaseService. Here, we are using the dependency inject pattern via a constructor to map the concrete objects with abstraction:

Now, after defining the service abstraction services, we could implement the RestaurantService in the following way:

Similarly, you could write the implementation for other entities. This code is a basic implementation and you might add various implementations and behaviors in the production code.