Template Method mode
origin
Delphi's Template Method mode is based on the virtual function of Object Pascal.
purpose
Define a framework for a set of algorithms to define some subclasses that do not change the algorithm structure.
motivation
· Better packaging strategic policy and distribute to different agents.
• Better code reuse of complex algorithms, base classes encapsulated parts, and allow subclasses to achieve overloaded partial behavior methods.
• Better through the scope of the scope of the scope, but the Template Method mode is only allowed to be called by the base class.
UML illustration:
application
Let's take a look at several Template Method mode VCL components. In the following example, abstract class TSTREAM in the VCL component implements a copy method CopyFrom (), and the template method CopyFrom () contains the necessary algorithms for the current copy. TSTREAM claims the READ () and WRITE () methods as abstract methods, and will deliver the specific subclass of it. CopyFrom () Access Readput (), Write (), readbuffer (), WriteBuffer () is a template method. They will provide static and simple read () and Write () imaginary interface. READ () and Write () are executed in the derived class in the derived class.
For more detailed implementation code, please refer to the Classes.Pas unit of VCL, abstract class TSTREAM and specific stream: TcustomMemMemoryStream / TMemoryStream and Tstringstream. Usually the Template method is defined in the base class, and the derived operation is defined as the virtual method, and you only need to overload the extension in the subclass. Yes, the interface does not support the Template method.
{Abstract class TSTREAM}
TSTREAM = Class (TOBJECT)
Private
...
protected
Procedure setsize (newsize: longint); virtual;
public
// Source supported the original method
Function Read (var buffer; count: longint; virtual; abstentract;
Function Write (CONST BUFFER): Longint; Virtual; ABSTRACT
Function seek (offset: longint; origin: word): longint; virtual; abstentract;
// Template method
Procedure Readbuffer (VAR Buffer; Count: longint);
Procedure WriteBuffer (Const Buffer; Count: longint);
/ / Encapsulate the stream of stream of the template method
Function CopyFrom (Source: TSTREAM; Count: longint): Longint
...
END;
// Specific class
TStringStream = Class (TSTREAM)
...
public
Constructor Create (const astring: string);
// The specific class implements overloaded methods
Function Read (VAR Buffer; Count: Longint; OVERRIDE): LONGINT;
...
Function Write (CONST BUFFER): Longint; OVERRIDE;
...
END;
---------
{TSTREAM} // Abstract class ...
// Template method
Procedure TSTREAM.Readbuffer (VAR Buffer; Count: longint);
Begin
IF (Count <> 0) and (buffer, count) <> count) THEN
Raise EREADERROR.CREATE (Sreaderror);
END;
Procedure TStream.writebuffer (Const Buffer; Count: longint);
Begin
IF (count <> 0) and (write (buffer, count) <> count) THEN
Raise EwriteError.create (SWRITEERROR);
END;
Function TSTREAM.COPYFROM (Source: TSTREAM; Count: longint): Longint
Const
Maxbufsize = $ f000;
VAR
BUFSIZE, N: Integer;
Buffer: pchar;
Begin
If count = 0 THEN
Begin
Source.position: = 0;
Count: = source.size;
END;
RESULT: = Count;
IF count> maxbufsize the buffsize: = maxbufsize else buffsize: = count
GetMem (buffer, bufsize);
Try
While Count <> 0 DO
Begin
IF count> buffsize kiln: = bufsize else n: = count;
Source.Readbuffer (buffer ^, n);
Writebuffer (buffer ^, n);
Dec (count, n);
END;
Finally
FreeMem (buffer, bufsize);
END;
END;
---------
{TSTRINGSTREAM} // Specific class
...
// The specific class implements the source of the source
Function TStringStream.read (var buffer; count: longint): longint
Begin
Result: = Length (fdataString) - fposition;
If Result> Count the result: = count
Move (pchar (@fdataString [fposition 1]) ^, buffer, result);
Inc (fposition, result);
END;
Function TStringStream.write (CONST BUFFER): longint
Begin
RESULT: = Count;
SetLength (fdataString, (fposition result));
Move (Buffer, Pchar (@fdataString [fposition 1]) ^, result);
Inc (fposition, result);
END;