Template pattern
Template pattern: belongs to behavioral design pattern, is one of the design patterns used more, more simple design pattern. While you may not yet know how to write in template mode, you may already have used it. Let’s start with a definition: Template pattern: Defines the skeleton of an algorithm in an operation and deferred some steps of the algorithm to subclasses so that subclasses can redefine specific steps of the algorithm without changing the structure of the algorithm. In plain English, I define some behavior rules in an abstract superclass, and specify the order in which these behavior rules are executed. As a subclass, you just need to implement the specifics of the behavior rules I define for your situation. Take a simple example: I have stipulated that the following things should be done before going to bed at night: lie in bed, brush your teeth, put on your pajamas, and the order of doing these things is to brush your teeth -> change your pajamas -> lie in bed, and you just need to do these things according to your actual situation, like
- Someone uses black toothpaste and a regular toothbrush, then puts on silk pajamas and lies down on his Mattress
- Someone uses Crest + electric toothpaste, then changes into the emperor’s new clothes and lies down on his bunk
Now as the music box listed company’s engineering department boss you, received the task from the superior, said that the customer wants to make music box!! And there were two of them. At this time, you disdain, (ˉ▽) just two, so easy. Here’s a standard design guide for music boxes
The original way
public abstract class MusicBox {
// Turn on the switch
abstract void start(a);
// Play music
abstract void sing(a);
// The decorations on the music box begin to move, the windmill turns, and the characters dance
abstract void action(a);
// Turn off the switch
abstract void end(a);
// Make the music box work
abstract void play(a);
}
Copy the code
Concrete realization of two kinds of music boxes:
public class Box1 extends MusicBox{
@Override
void start(a) {
System.out.println("Turn on the start switch of the first music box.");
}
@Override
void sing(a) {
System.out.println("Play City in the sky.");
}
@Override
void action(a) {
System.out.println("The windmill on the music box is turning.");
}
@Override
void end(a) {
System.out.println("Turn off the start switch on the first music box.");
}
@Override
void play(a) {
this.start();
this.sing();
this.action();
this.end(); }}public class Box2 extends MusicBox{
@Override
void start(a) {
System.out.println("Turn on the start switch of the second music box.");
}
@Override
void sing(a) {
System.out.println("Playing my dream wedding.");
}
@Override
void action(a) {
System.out.println("Couple on the music box starts dancing.");
}
@Override
void end(a) {
System.out.println("Turn off the start switch for the second music box.");
}
@Override
void play(a) {
this.start();
this.sing();
this.action();
this.end(); }}Copy the code
Demonstrate two types of music boxes to customers:
public class Client {
public static void main(String[] args) {
MusicBox box1 = new Box1();
box1.play();
System.out.println("= = = = = = = = = = = = = = = = = = =");
MusicBox box2 = newBox2(); box2.play(); }}Copy the code
Running results:
Wow, that seems to be the perfect client function. But a closer look shows that the methods used to make the music box work are exactly the same in the two music box implementation classes. Well, well, well, well, shouldn’t it be in the abstract superclass? All right? Come on, play it!
Template mode
public abstract class MusicBox {
// Turn on the switch
abstract void start(a);
// Play music
abstract void sing(a);
// The decorations on the music box begin to move, the windmill turns, and the characters dance
abstract void action(a);
// Turn off the switch
abstract void end(a);
// Make the music box work
public void play(a){
this.start();
this.sing();
this.action();
this.end(); }}public class Box1 extends MusicBox{
@Override
void start(a) {
System.out.println("Turn on the start switch of the first music box.");
}
@Override
void sing(a) {
System.out.println("Play City in the sky.");
}
@Override
void action(a) {
System.out.println("The windmill on the music box is turning.");
}
@Override
void end(a) {
System.out.println("Turn off the start switch on the first music box."); }}public class Box2 extends MusicBox{
@Override
void start(a) {
System.out.println("Turn on the start switch of the second music box.");
}
@Override
void sing(a) {
System.out.println("Playing my dream wedding.");
}
@Override
void action(a) {
System.out.println("Couple on the music box starts dancing.");
}
@Override
void end(a) {
System.out.println("Turn off the start switch for the second music box."); }}Copy the code
The presentation to the customer is the same as before:
public class Client {
public static void main(String[] args) {
MusicBox box1 = new Box1();
box1.play();
System.out.println("= = = = = = = = = = = = = = = = = = =");
MusicBox box2 = newBox2(); box2.play(); }}Copy the code
Running results:
Here’s what I said at the beginning:start(),sing(),action(),end()
These are the rules, andplay()
This is the order in which the rules are executed. This is the template pattern, isn’t it so easy? Using the template pattern results in the same way as the original method, and the template pattern reduces code redundancy and makes the code more concise.
To optimize the
- In the template method, the basic method and design as far as possible
protected
, other properties and methods should not be set toprotected
- In order to prevent malicious operation, template method a version will be added
final
The basic methods are the rules I mentioned above, and the template methods are the ways I define the order in which the rules are executed, so the above code can be written as:
public abstract class MusicBox {
// Turn on the switch
protected abstract void start(a);
// Play music
protected abstract void sing(a);
// The decorations on the music box begin to move, the windmill turns, and the characters dance
protected abstract void action(a);
// Turn off the switch
protected abstract void end(a);
// Make the music box work
final public void play(a){
this.start();
this.sing();
this.action();
this.end(); }}public class Box1 extends MusicBox{
@Override
protected void start(a) {
System.out.println("Turn on the start switch of the first music box.");
}
@Override
protected void sing(a) {
System.out.println("Play City in the sky.");
}
@Override
protected void action(a) {
System.out.println("The windmill on the music box is turning.");
}
@Override
protected void end(a) {
System.out.println("Turn off the start switch on the first music box."); }}public class Box2 extends MusicBox{
@Override
protected void start(a) {
System.out.println("Turn on the start switch of the second music box.");
}
@Override
protected void sing(a) {
System.out.println("Playing my dream wedding.");
}
@Override
protected void action(a) {
System.out.println("Couple on the music box starts dancing.");
}
@Override
protected void end(a) {
System.out.println("Turn off the start switch for the second music box."); }}Copy the code
The presentation to the customer is the same as before:
public class Client {
public static void main(String[] args) {
MusicBox box1 = new Box1();
box1.play();
System.out.println("= = = = = = = = = = = = = = = = = = =");
MusicBox box2 = newBox2(); box2.play(); }}Copy the code
Running results:
advantages
- Encapsulate invariant parts and extend variable parts
- Extract common parts of code for easy maintenance
- The behavior is controlled by the parent class and implemented by the child class
disadvantages
- Reversing our convention, the results of the execution of a subclass affect the results of the parent class, that is, the subclass affects the parent class
- If the order of execution needs to change, modify the code of the abstract class
extension
After seeing the two music boxes in the demo, the customer put forward a new demand: some of the music boxes we play sky City have movable decorations, such as windmill and water wheel, while some have no movable decorations. What’s the matter? Looking at the customer’s demand, you fell into a deep thought. It is too waste of resources to open a new category for such a small difference. There must be some way to make this compatible
Hook method
Yes, you can make a music box produce different products based on different decorations by using hooks in an abstract class. Here, add a hook method to determine whether there are movable decorations to control, so we can modify it to look like this:
public abstract class MusicBox {
// Turn on the switch
protected abstract void start(a);
// Play music
protected abstract void sing(a);
// The decorations on the music box begin to move, the windmill turns, and the characters dance
protected abstract void action(a);
// Turn off the switch
protected abstract void end(a);
// Determine if there is a movable decoration - the hook function here changes the internal result through external changes
protected boolean haveActionThings(a){
return true;
}
// Make the music box work
final public void play(a){
this.start();
this.sing();
if(this.haveActionThings()) {
this.action();
}
this.end(); }}public class Box1 extends MusicBox{
private boolean actionThingsTag = true;
@Override
protected void start(a) {
System.out.println("Turn on the start switch of the first music box.");
}
@Override
protected void sing(a) {
System.out.println("Play City in the sky.");
}
@Override
protected void action(a) {
System.out.println("The windmill on the music box is turning.");
}
@Override
protected void end(a) {
System.out.println("Turn off the start switch on the first music box.");
}
@Override
protected boolean haveActionThings(a) {
return actionThingsTag;
}
public void setActionThingsTag(boolean actionThingsTag) {
this.actionThingsTag = actionThingsTag; }}public class Box2 extends MusicBox{
@Override
protected void start(a) {
System.out.println("Turn on the start switch of the second music box.");
}
@Override
protected void sing(a) {
System.out.println("Playing my dream wedding.");
}
@Override
protected void action(a) {
System.out.println("Couple on the music box starts dancing.");
}
@Override
protected void end(a) {
System.out.println("Turn off the start switch for the second music box."); }}public class Client {
public static void main(String[] args) {
Box1 box1 = new Box1();
box1.play();
System.out.println("= = = = = = = = = = = = = = = = = = =");
Box1 box11 = new Box1();
box11.setActionThingsTag(false);
box11.play();
System.out.println("= = = = = = = = = = = = = = = = = = =");
Box2 box2 = newBox2(); box2.play(); }}Copy the code
Running results:
conclusion
The template method pattern is framed by the parent class, and the subclass overrides the parent class to make the subclass more focused on the implementation of business code. Important core algorithms can be designed as template methods, with other details implemented in subclasses.
One thousand readers have one thousand Hamlet, the above is purely in my personal learning experience, if there is any wrong, please point out, let me learn a wave, correct mistakes, thank you!