Skip to content

guide usecase

devonfw-core edited this page Dec 13, 2022 · 11 revisions

UseCase

A use-case is a small unit of the logic layer responsible for an operation on a particular entity (business object). We leave it up to you to decide whether you want to define an interface (API) for each use-case or provide an implementation directly.

Following our architecture-mapping (for classic and modern project), use-cases are named Uc«Operation»«BusinessObject»[Impl]. The prefix Uc stands for use-case and allows to easily find and identify them in your IDE. The «Operation» stands for a verb that is operated on the entity identified by «BusinessObject». For CRUD we use the standard operations Find and Manage that can be generated by CobiGen. This also separates read and write operations (e.g. if you want to do CQSR, or to configure read-only transactions for read operations).

In our example, we choose to define an interface for each use-case. We also use *To to refer to any type of transfer object. Please follow our guide to understand more about different types of transfer object e.g. Eto, Dto, Cto

Find

The UcFind«BusinessObject» defines all read operations to retrieve and search the «BusinessObject». Here is an example:

public interface UcFindBooking {
  //*To = Eto, Dto or Cto
  Booking*To findBooking(Long id);
}

Manage

The UcManage«BusinessObject» defines all CRUD write operations (create, update and delete) for the «BusinessObject». Here is an example:

public interface UcManageBooking {

  //*To = Eto, Dto or Cto
  Booking*To saveBooking(Booking*To booking);

  void deleteBooking(Long id);

}

Custom

Any other non CRUD operation Uc«Operation»«BusinessObject» uses any other custom verb for «Operation». Typically, such custom use-cases only define a single method. Here is an example:

public interface UcApproveBooking {

  //*To = Eto, Dto or Cto
  void approveBooking(Booking*To booking);

}

Implementation

The implementation should carry its own name and the suffix Impl and is annotated with @Named and @ApplicationScoped. It will need access to the persistent data which is done by injecting the corresponding repository (or DAO). Furthermore, it shall not expose persistent entities from the data access layer and has to map them to transfer objects using the bean-mapper. Please refer to our bean mapping, transfer object and dependency injection documentation for more information. Here is an example:

@ApplicationScoped
@Named
public class UcManageBookingImpl implements UcManageBooking {

  @Inject
  private BookingRepository bookingRepository;

  @Override
  public void deleteBooking(Long id) {

    LOG.debug("Delete Booking with id {} from database.", id);
    this.bookingRepository.deleteById(id);
  }
}

The use-cases can then be injected directly into the service.

@Named("BookingmanagementRestService")
@Validated
public class BookingmanagementRestServiceImpl implements BookingmanagementRestService {

  @Inject
  private UcFindBooking ucFindBooking;

  @Inject
  private UcManageBooking ucManageBooking;

  @Inject
  private UcApproveBooking ucApproveBooking;
}

Internal use case

Sometimes, a component with multiple related entities and many use-cases needs to reuse business logic internally. Of course, this can be exposed as an official use-case API but this will imply using transfer-objects (ETOs) instead of entities. In some cases, this is undesired e.g. for better performance to prevent unnecessary mapping of entire collections of entities. In the first place, you should try to use abstract base implementations providing reusable methods the actual use-case implementations can inherit from. If your business logic is even more complex and you have multiple aspects of business logic to share and reuse but also run into multi-inheritance issues, you may also just create use-cases that have their interface located in the impl scope package right next to the implementation (or you may just skip the interface). In such a case, you may define methods that directly take or return entity objects. To avoid confusion with regular use-cases, we recommend to add the Internal suffix to the type name leading to Uc«Operation»«BusinessObject»Internal[Impl].

Clone this wiki locally