I have several services and each of these services has interfaces for each. I need to add a shared execution strategy here. By designating two classes with the same inheritance relationship as primary and secondary, one should be executed according to a branch.

Example of the services:

interface FirstService { 
    abstract String doSomething 

class FirstServiceImpl1 implements FirstService { ... }
class FirstServiceImpl2 implements FirstService { ... }
class FirstServiceImpl3 implements FirstService { ... }

interface SecondService { 
    abstract String doSomething(); 
    abstract void doAnotherThing();
class SecondServiceImpl1 implements SecondService { ... }
class SecondServiceImpl2 implements SecondService { ... }

Example of the shared logic:

class BranchExecutionForFirstService implements FirstService {
    private FirstService primaryService;
    private FirstService secondaryService;
    private Predicate branch;

    // override
    String doSomething() {
       if (branch()) {
          return primary.doSomething();  
       } else {
          return secondary.doSomething();

Example of the way I want to use:

class MyController() {
    FirstService firstServie;   // BranchExecutionForFirstService is injected but this controller does not know the branch.

There is no relationship between the FirstService and the SecondService but they need to have the same way of execution branch like above. Very simple way to achieve this is just to add another branch service: BranchExecutionForSecondService but I don’t like this way because there will be need to write third and forth as services are added.

What should I do to gracefully achieve this?



Use separation of concerns. Make selecting a service based on a predicate a separate responsibility:

class ServiceSelector<TService> {
    TService whenPredicateTrue;
    TService alternative;
    Predicate selectionCriterium;

    TService select() {
        if selectionCriterium() {
            return whenPredicateTrue;
        } else {
            return alternative;

(Perhaps there are more operations that can implement this interface.)

For each service interface make a proxy that forwards its methods to the object returned by the selector:

class FirstServiceProxy: FirstService {
    ServiceSelector<FirstService> target;

    String doSomething() {
        return target

And the same for SecondService.

Java does have DynamicProxy which can help here. C# has reflection, emitting code, dynamic, and, if I remember correctly, the BouncyCastle library.


This is a first step of “programming” on a higher level. Nice.

However it seems the start of a Business Process Model Notation. A flow of control if Branch then FirstServ else SecondServ.

I would for that focus on BPMN, in a light weight form. A graph is made, XML stored. There are some library/engine providers.

Event logic, timed jobs, more complex flow. Control of the flow.

However if you do not really intend to structure business processes, do not pick BPMN.

I offer this answer, as what you want to achieve seems like a step wise improvement/refactoring without the benefit of an overall controlling.
I might be wrong.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *