definition of a pattern
Defines the framework for an algorithm in an operation, and delays some steps into subclasses. Enables subclasses to redefine some specific steps of the algorithm without altering the structure of an algorithm.
Usage Scenarios
1, many sub-categories have a public method, and the logic is basically the same.
2, the important, complex algorithm, the core algorithm can be designed as a template method, the surrounding details of the function is implemented by each sub-class.
3, refactoring, template method pattern is a frequently used pattern, the same code is extracted into the parent class, and then through the hook function to constrain its behavior.
UML class Diagram
Role Description
AbstractClass: Abstract class, defines a set of algorithm framework.
CONCRETECLASS1: Concrete implementation Class 1;
CONCRETECLASS2: Concrete implementation Class 2;
Simple Example
The template approach is actually encapsulating an algorithmic framework, just like a set of templates. Subclasses can have different algorithm implementations and replace the algorithm without the framework being modified. Let's take a brief look at the template method by opening the computer. The entire process of opening the computer is relatively stable, first turn on the computer power, the computer detects its own state without problems will enter the operating system, the user can be authenticated after logging on to the computer, the following we use the template method to simulate this process.
Package com.dp.example.templatemethod;/** * Abstract Computer * @author Mrsimple * */public abstract class Abstractcomputer { protected void PowerOn () {System.out.println ("Power on"); } protected void Checkhardware () {System.out.println ("hardware Check"); } protected void Loados () {System.out.println ("Load operating system"); } protected void Login () {System.out.println ("Small white computer without authentication, direct access to the system"); /** * Start the computer method, the steps are fixed to turn on power, system check, load operating system, user login. This method is final and prevents the algorithm framework from overwriting. */public final void StartUp () {System.out.println ("------start------"); PowerOn (); Checkhardware (); Loados (); Login (); SYSTEM.OUT.PRINTLN ("------Boot END------"); }}package com.dp.example.templatemethod;/** * Farm Computer * * @author mrsimple */public class Codercomputer extends Abstractco Mputer {@Override protected void login () {System.out.println ("code farmer only needs to authenticate with user and password"); }}package com.dp.example.templatemethod;/** * Military Computer * * @author MrsImple */public class Militarycomputer extends Abstractcomputer {@Override protected void Checkhardware () { Super.checkhardware (); SYSTEM.OUT.PRINTLN ("Check hardware Firewall"); } @Override protected void login () {System.out.println ("complex user authentication such as fingerprint"); }}package Com.dp.example.templatemethod;public class Test {public static void main (string[] args) {abstractcom Puter comp = new Codercomputer (); Comp.startup (); comp = new Militarycomputer (); Comp.startup (); }}
The output is as follows:
------start------Turn on the power hardware check load operating system code farmers only need user and password authentication can be------boot END------------start------ Turn on the power hardware check to check the hardware firewall loaded into the operating system for fingerprint and other complex user authentication------boot END------
As can be seen in the above example, there are some fixed steps in the startup method, in order to turn on the power supply, check the hardware, load the system, user login Four steps, these four steps is the computer boot process will not change the four processes. But the implementation of these steps by different users may vary, so they can be implemented differently. And the startup is the final method, that is to ensure that the algorithm framework can not be modified, the implementation of the specific algorithm can be flexibly changed. In the startup of these algorithms we can be called a routine, can be called a template method. Therefore, the template method is the framework that defines the algorithm in an operation, and some steps are deferred to the subclass. Enables subclasses to redefine some specific steps of the algorithm without altering the structure of an algorithm. :
Source Analysis
In Android, a typical class that uses the template method and is familiar to us is asynctask, for a more detailed analysis of Asynctask please go to the Android Asynctask usage and source analysis, we only analyze the template method pattern used in this class.
when using Asynctask, we all have to know the time-consuming method to put in Doinbackground(Params... params), if you want to do some similar initialization before doinbackground, you can write it in the OnPreExecute method, When the Doinbackground method executes, the OnPostExecute method is executed, and we only need to build the Asynctask object and execute the Execute method. As we can see, it is actually a framework for the entire execution process, and the specific implementation requires subclasses to complete. And it executes the algorithm framework is fixed, call execute will execute onpreexecute,doinbackground,OnPostExecute, of course, you can also pass onprogressupdate to update the progress. We can simply understand the pattern as:
Here we look at the source code, first we look at the implementation of the asynchronous task portal, namely the Execute method:
Public final Asynctask<params, Progress, result> execute (params ... params) {return Executeonexecutor (sdefaul Texecutor, params); Public final Asynctask<params, Progress, result> executeonexecutor (Executor exec, params ... params) {if (mstatus! = status.pending) {switch (mstatus) {case running:th Row new IllegalStateException ("Cannot execute task:" + "The task is already running."); Case Finished:throw New IllegalStateException ("Cannot Execute task:" + "The task has already been executed" + "(a task can is executed only once)"); }} mstatus = status.running; OnPreExecute (); Mworker.mparams = params; Exec.execute (mfuture); return this; }You can see that the Execute method (the method for the final type) called the Executeonexecutor method, in which the state of the task is judged, and if not the pending state throws an exception, which explains why Asynctask can only be executed once, So if the task has been executed, then its state will becomefinished. Continuing down, we see that the OnPreExecute method was first executed in the Executeonexecutor method , and that the method executes on the UI thread. The params parameter is then passed to the Mparams field of the Mworker object, and then the Exec.execute (mfuture) method is executed.
What about Mworker and mfuture? In fact Mworker just implemented the callable interface, and added a parameter array field, about callable and futuretask data, refer to the Java runnable, callable, future, Futuretask the differences and examples, let's take a look at the trace code, we can see that both of these fields are initialized in the constructor,
Public Asynctask () {mworker = new workerrunnable<params, result> () {public Result call () thro WS Exception {Mtaskinvoked.set (true); Process.setthreadpriority (Process.thread_priority_background); Return Postresult (Doinbackground (mparams)); } }; Mfuture = new Futuretask<result> (mworker) {@Override protected void done () {T ry {Final result result = Get (); postresultifnotinvoked (result); } catch (Interruptedexception e) {ANDROID.UTIL.LOG.W (Log_tag, E); } catch (Executionexception e) {throw new RuntimeException ("An error occured while executing doinbackg Round () ", E.getcause ()); } catch (Cancellationexception e) {postresultifnotinvoked (null); } catch (Throwable t) { throw new RuntimeException ("An error occured while executing" + "Doinbackgrou nd () ", t); } } }; }Simply put, mfuture wraps the Mworker object, invokes the call method of the Mworker object, and returns it to the caller.
For a more detailed analysis of Asynctask, please With the use of Asynctask in Android and source Analysis , we only analyze template method patterns here. In summary, the call method is called in a child thread, and the Doinbackground method is called in the call method, so Doinbackground executes on the child thread. Doinbackground will return the results and eventually be delivered to the UI thread via Postresult.
Let's look at the implementation of Postresult:
Private result Postresult (result result) {Message message = Shandler.obtainmessage (Message_post_result, New Asynctaskresult<result> (this, Result)); Message.sendtotarget (); return result; } private static Class Internalhandler extends Handler {@SuppressWarnings ({"Unchecked", "Rawuseofparameterizedt Ype "}) @Override public void Handlemessage (Message msg) {asynctaskresult result = (asynctaskresu LT) Msg.obj; Switch (msg.what) {case Message_post_result://There are only one RESULT Result.mTask.finish (Result.mdata[0]); Break Case MESSAGE_POST_PROGRESS:result.mTask.onProgressUpdate (Result.mdata); Break }}} private void finish (result result) {if (iscancelled ()) {oncancelled (result); } else {OnPostExecute (resULT); } mstatus = status.finished; }
As you can see, Postresult is sending a message (Msg.what = = Message_post_result) to the Shandler,shandler type Internalhandler type, When Internalhandler receivedthe Result.mTask.finish (Result.mdata[0]) method is called when a message of type Message_post_result is used. We can see result as Asynctaskresult type, the source code is as follows:
@SuppressWarnings ({"Rawuseofparameterizedtype"}) private static class Asynctaskresult<data> { final Asynctask Mtask; Final data[] Mdata; Asynctaskresult (asynctask task, data ... data) { mtask = task; Mdata = data; } }
You can see that Mtask is the Asynctask object, callingThe Asynctask object's Finish method calls the OnPostExecute, and this time the entire execution process is complete.
In short, the Execute method inside encapsulates the OnPreExecute, Doinbackground, onpostexecute This algorithm framework, the user can according to their own needs to overwrite these methods, so that users can easily use asynchronous tasks to complete the time-consuming operation, You can also use OnPostExecute to complete the task of updating the UI thread.
Advantages and DisadvantagesAdvantages:1. Package invariant part, extend variable part 2. Extracting public parts code for easy maintenance
Disadvantages:the template method can make the code reading difficult, which makes the heart feel difficult to understand.