Helps you to improve the readability of your code when you are using the Decorator pattern.
Makes your code much more readable!
For Gradle, add the following dependency in build.gradle:
dependencies {
implementation 'io.github.chinhung:pointwave:1.0.0'
}For Maven, add the following dependency in pom.xml:
<dependency>
<groupId>io.github.chinhung</groupId>
<artifactId>pointwave</artifactId>
<version>1.0.0</version>
</dependency>If you use other build tool, please visit Maven Central.
First, call the static method PointWave.decoratee to initialize the decoratee. And then, call the method decorated with the decorator function as the argument in lambda expression, one by one. The last step is to call complete method, which returns the decorated object:
Objectdecorated = PointWave.decoratee(decoratee)
.decorated(decoratee -> decorator1Factory.create(decoratee, param1))
.decorated(decoratee -> Decorator2.createInstance(decoratee, param2))
.decorated(decoratee -> newDecorator3(decoratee, param3))
.complete();- the decorator function is a function which receives the decoratee and returns the decorated object
- the decorator functions will be applied following the "First In, First Out" rule (in this example, the inner layer of the decorated object is
decoratee, the second layer isDecorator1, the third layer isDecorator2and the outer layer isDecorator3) - provides generic support
publicclassHelloWorld {
@OverridepublicStringtoString() {
return"Hello World!";
}
}publicclassNameDecoratorextendsHelloWorld {
privatefinalHelloWorlddecoratee;
privatefinalStringname;
publicNameDecorator(finalHelloWorlddecoratee, finalStringname) {
this.decoratee = decoratee;
this.name = name;
}
@OverridepublicStringtoString() {
returndecoratee.toString() + " " + name + "!";
}
}publicclassTodayDecoratorextendsHelloWorld {
privatefinalHelloWorlddecoratee;
privatefinalStringtoday;
publicTodayDecorator(finalHelloWorlddecoratee, finalStringtoday) {
this.decoratee = decoratee;
this.today = today;
}
@OverridepublicStringtoString() {
returndecoratee.toString() + " Today is " + today + "!";
}
}HelloWorlddecorated = PointWave.decoratee(newHelloWorld())
.decorated(decoratee -> newNameDecorator(decoratee, "John Doe"))
.decorated(decoratee -> newTodayDecorator(decoratee, "Friday"))
.complete();
assertEquals("Hello World! John Doe! Today is Friday!", decorated.toString());The code is not readable if you decorate the object manually in the following coding style:
- a single line code
Objectdecorated = newDecorator3(Decorator2.createInstance(decorator1Factory.create(decoratee, param1), param2), param3);- deeply nested code
Objectdecorated = newDecorator3(
Decorator2.createInstance(
decorator1Factory.create(
decoratee, param1
), param2
), param3
);We could improve the readability of the code by using a temporary local variable:
Objectdecorated = decoratee;
decorated = decorator1Factory.create(decorated, param1);
decorated = Decorator2.createInstance(decorated, param2);
decorated = newDecorator3(decorated, param3);However, the code style is imperative.
The code style is continuous and similar to the builder pattern, which is more meaningful. Also, an appropriately designed api brings more intention of the code to the reader:
Objectdecorated = PointWave.decoratee(decoratee)
.decorated(decoratee -> decorator1Factory.create(decoratee, param1))
.decorated(decoratee -> Decorator2.createInstance(decoratee, param2))
.decorated(decoratee -> newDecorator3(decoratee, param3))
.complete();Even more, the intention would be more clear if the decorator functions were named appropriately:
FunctionwithDecorator1 = decoratee -> decorator1Factory.create(decoratee, param1);
FunctionwithDecorator2 = decoratee -> Decorator2.createInstance(decorated, param2);
FunctionwithDecorator3 = decoratee -> newDecorator3(decorated, param3);
Objectdecorated = PointWave.decoratee(decoratee)
.decorated(withDecorator1)
.decorated(withDecorator2)
.decorated(withDecorator3)
.complete();- abstract
Decorateeas interface - refactor the code to functional style
- use
Github Actionsto build and test the code - write
Javadoc
- use
Git Flowin this project - incremental delivery
