Title: Simple example for the COMPOSITE Design Pattern
Question: What is the Composite Design Pattern ? How do you copy a directory with all subdirectories in a simple way ?
Answer:
The COMPOSITE Design Pattern lets clients treat individual
objects and compositions of objects uniformly
(according to Gamma, Helm, Johnson and Vlissides
"Design Patterns", Addision-Wesley, 1995. Allthough
this book now is nearly 8 years old, it is even in
the new DOT NET World still important.)
The idea is to define a Composite Class
aComponentClass = class
..
procedure DoSomething; virtual;
end;
aCompositeClass = class(aComponentClass)
aList: tList; // List of "aComponentClass" Objects
procedure DoSomething; override;
...
end;
Now you can call a single class method
aComponentClass.DoSomething;
in any case, whether the class is a composite class or not.
The method "DoSomething" of the CompositeClass for example
calls "DoSomething" for every item of the list.
This allows you to ignore the difference between compositions
of objects and individual objects.
A simple example for a composition is a directory : a
directory is a composition of files. A simple implementation
of a class that copies a file or a complete directory with
all subdirectories looks like this :
uses Classes,SysUtils,..;
tFile = class
public
fName : string;
public
constructor Create(Name : string);
procedure Copy(DstDir : string); virtual;
property Name : string read fName;
end;
tDirectory = class(tFile)
private
FileList : tList;
public
constructor Create(Name : string);
destructor Destroy;
procedure Copy(DstDir : string); override;
property Name;
end;
{ tFile }
constructor tFile.Create(Name: string);
begin
fName:=Name;
end;
procedure tFile.Copy(DstDir: string);
var SrcFilename,DstFilename : string;
begin
SrcFilename:=fName;
DstFilename:=IncludeTrailingPathDelimiter(DstDir)+
ExtractFilename(fName);
if FileExists(SrcFilename) then
Windows.CopyFile(PChar(SrcFilename),PChar(DstFilename),false);
end;
{ tDirectory }
procedure tDirectory.Copy(DstDir: string);
var i : integer;
RelPath : string;
begin
if not DirectoryExists(DstDir) then
ForceDirectories(DstDir);
for i:=0 to FileList.Count-1 do
if tFile(FileList[i]) is tDirectory then
begin
RelPath:=ExtractRelativePath(IncludeTrailingPathDelimiter(Name),
tDirectory(FileList[i]).Name);
tDirectory(FileList[i]).Copy(DstDir+'\'+RelPath)
end else
tFile(FileList[i]).Copy(DstDir)
end;
constructor tDirectory.Create(Name: string);
var Root,s : string;
sr : tSearchRec;
begin
inherited Create(Name);
FileList := tList.Create;
Root:=IncludeTrailingPathDelimiter(Name);
s:=Root+'*.*';
if FindFirst(s, faAnyFile , sr) = 0 then
begin
repeat
if (sr.Name = '.') or (sr.Name = '..') then continue;
if ((sr.Attr and faDirectory) 0)
then FileList.Add(tDirectory.Create(Root+sr.Name))
else FileList.Add(tFile.Create(Root+sr.Name));
until FindNext(sr) 0;
FindClose(sr);
end;
end;
destructor tDirectory.Destroy;
var i : integer;
begin
for i:=0 to FileList.Count-1 do
tFile(FileList[i]).Destroy;
FileList.Free;
end;