Functional Chain of Responsibility

Useful design pattern at functional way at Java

Darr Mirr
7 min readMar 9, 2021

Introduction

Imaging you have to visit a doctor. You call to emergency service and make appointment to visit therapist tomorrow. Next day you go to hospital and face with trouble. There is only one door and no nameplate on it! It makes you very confuse. You have no choice and open the door and ask for therepist. Doctor tell you that he is a surgeon. So you ask where to find therepist. Unfortunately, he don’t know. It is not my responsibility what he said. You can see at next door he added at last. You notice another door at the room. There is procedure room behind the next door and nurse have no idea about therepist accomodation. You get nothing at third door. You open forth door and finally find your doctor!

What the strange hospital, is not it? Nevertheless, it is normal at object oriented programming languages.

And such behavior is called Chain of Responsibility.

But what about real life? Do you behave at hospital the same way? I think, no. Each doctor office is connected to common room, so patient does not require to go from one room to another. And usually people read nameplate on door and always know which doctor is behind the door.

Functional version of Chain of Responsibility pattern is behave as people at real life. Function at chain is not invoked if input value does not correspond to function’s responsibility.

Chain of Responsibility structure

Let’s look on scheme of patient visit to hospital at object oriented programming (OOP):

Scheme of patient visit to hospital at OOP world

Doctor’s office is the place where business code is executed if handler’s responsibility condition evaluates true. Therefore, doctor’s office represent handler.

Patient is input object to first handler in chain. It is also called request. Request is sent by client. Usually, client represent function or method at application code.

So, pattern have 3 elements:

  • handler
  • request
  • client

Replace element’s names on scheme by new one:

Chain of handlers. (Client is omited here)

Handler consist of 3 parts:
- handler executor (execute business code)
- handler’s responsibility condition
- next handler reference

Handler’s internal structure

It is classic pattern structure. There are numerous variations of this structure. For example, next handler may be invoked even condition at previous handler has evaluated true. Servlet filters have such variation.

Finally, client does not work with handlers directly. It works with its interface or abstract class that hide implementation details from client. Therefore, we can add or remove hadlers from chain without impact to client’s code.

Chain of Responsibility pattern scheme at OOP

Pros and Cons of OOP pattern version

+ Decouple client’s and handler’s code
+ Write modular and reusable handler’s code.
+ Handler’s code become more extendable and easy to support
+ Having different request processing strategies at processing time

– handler has more than one responsibility
– usually implementation require to create abstract class
– handler store reference to another one at chain

At my opinion, the last cons is more awful. I have a lot of cases when developer forget to invoke next filter at servlet filter chain. It leads that processing of all http requests is broken. It looks like next door is placed inside doctor’s office at hospital example. And patient have to visit each doctor before he gets the right one. Moreover, patient is not able to visit his doctor if for example, surgeon’s room has no door to next one!

Functional pattern version

Let’s look on pattern scheme at functional programming:

Chain of responsibility pattern scheme at FP

Client’s request passes chain by if it does not meet chain’s responsibility requirement. It looks like a patient goes down passage towards to his doctor’s office.

What is the main difference berween OOP and FP pattern implementations?

The main difference is handler have only one responsibility. It does not manage input object (request) direction at chain.

Let’s look at internal chain structure:

Internal chain structure

Chain consist of 2 parts:
- handler
- handler’s contract

Now handler consists only handler executor. It performs some actions if input object is passed to it. Handler’s contract make desicion whether pass request to handler or not.

Neither handler nor contract know about next chain. All chains combine to each other by function. It would be invoked if current one has not fit contract requirements.

Three Face of Function

Let’s have a look at main functions at Java before go to pattern implementation:

Three face of function at Java
  • Function has one input and one output.
  • Supplier has no input and one output.
  • Consumer has one input and no output.

Pattern FP implementation

Let’s start with java.util.function.Function example.

Three components should be implemented:

  • Chain
  • Handler
  • HandlerContract

Map scheme structure to code:

Chain structure at Java

According to scheme chain is only wrap Handler and HandlerContract. I add suffix Function to Handler’s name interface because there is another kind of function’s type at Java.

Let’s look at chain creation flow:

Chain → Handler → HandlerContract

Map creation flow steps to methods at interfaces:

Chain builder’s methods

Chain creation has finished after HandlerContract is set. I use Contract function for Handler’s contract one.

You can read about Contract function at my article on medium.com

Method chain is mark as default for this reasons:

  • It should store chain creation code
  • HandlerFunction interface already has one method because it extends Function one. So, lambda expression could be created only for interfaces that contains only one abstract method.

Next I add chain creation code:

Chain creation function

Let’s have a look at the first map method. HandlerContract wrap (obligate) handler function in order to test input value by condition defined at contract function.

Next map method create function that combine new chain and previous one. Previous chain would be invoked if new chain return empty object.

Finally, I define two utility methods in order to simplify chain creation:

Utility method as entry point of chain creation

Default chain is the last element at handler sequence. It has no contract and would be invoked if all contract functions at chain evaluate false.

Pattern in action

Now let’s write code to model patient visit to hospital.

Here is Hospital code snippet:

Hospital Interface

Doctor enumeration is list of doctor accomodated at hospital. Method directTo(Doctor doctor) is utility method that check patient direction at hospital. Method visit(Doctor doctor) is utility method that perform patient diagnose.

Here is Patient code snippet:

Patient class

Patient have information about appointment with doctor at hospital.

Finally, let’s look at model “patient visit to hospital” in action:

Patient visit hospital code sample

Local variable newPatient represent new hospital visitor. Local variable hospital represent chain of doctors that perform patient diagnose.

Code execution result may be vary according to random.nextInt() result.

Conclusion

The main adventages of this pattern implentation:

  1. Chain creation looks like a builder pattern. You create chain step by step. Moreover you can extend chain at any time just to invoke chain method.
  2. Unified pattern builder. You should not write own implementation of pattern. You only focus on your business code.
  3. Chain represent java.util.function.Function interface. Therefore you can easily to use it at any java standard library classes.
  4. Humanreadability. Functional code style tend to be concise. But a lot of fp programming languages introduce incredable amount of special symbols. And developer have to keep in mind all this symbols in order to write code. Java goes own way and try to use special symbols as minimal as possible. And encourage developer to write code by natural for human way using words.
  5. You can create multiply chains and combine it to each other.

Code samples and pattern implementation you can find at my repository on Github.com

--

--