Adapter style
Author: Cai Huanlin Date: Feb-25-2002
Abstract: From the risk of using foreign components, the principle of selection, to reduce future risks using Adapter style, this article illustrates how to use Delphi to actually Adapter style to improve programmability, and how to use Abstract Factory style to design dynamics Application (changing the behavior of the application during execution).
Introduction
Adapter is an interface-converted device, another name of the Wrapper, and the purpose of the Adapter style based on [GHJV95] definitions:
"Converting the interface of the category into another interface expected to allow the category that is originally in the interfacial incompatible problem and cannot work together." (Outdated from the Design Patterns Chinese version: Items Guide design mode)
In this article, I will design a practical Adapter category with Delphi, which is not to let the intercommoric categories can cooperate together, but package a category into a new category, let this category The interface is more in line with my needs.
Before introducing this category, let's look at a meaningful problem. Although it seems to have no relationship with the theme, it is actually related to the activity of the program, and has a little relationship with the motivation of Adapter.
Invention V.S.
Software developers must often face a wide range of needs. If there is a set of development tools that provide all the solutions are the best, but this is impossible, take Delphi, although it provides very Many VCL components, but it is still not enough to cope with all the needs of the project. At this time, the programming designer usually takes two solutions. One is written by itself, which may be new, or to refer or write others. Good components; the other is to use the ready-made components directly, do not make any modifications, which usually takes the effort to learn how to use it correctly.
In both ways, there is a timing, the bottom limit is: Do not rewrite it if you can't find the components you need. Because there are many ready-made VCL components, there are many ready-made VCL components, take some time to find more than the re-inventions. I believe that many people understand this reason, but including myself, sometimes I would rather write one, but I don't want to use ready-made components. why?
I believe that each program designer has a preference of the style and naming methods, and after this preference is a personal habit, it is inevitable to have some other styles, and it is not pleasing to the eye. Write must be better, so it will tend to write all the program code to solve the problem, so this mentality is understandable. Not only like this, there are other complicated reasons, such as: ready-made components that are not fully conforming to their needs, with program code to show their talents, the process of inventing the process is more interesting, studying others's program code is more boring, and possibly Also to endure the messages of messy messages, worry about the problem after maintenance ....
It is not possible to say that the difference in writing code is inevitable, but I believe that a little difference is acceptable, and the formulation of writing code standards is that they can reduce these differences. In the case of the factors just mentioned, most of them are related to individual character, only one exception, is also the most worthwhile, the maintenance. Imvise If you use a component to get your own program, what should I do if I find that the component is a bug? Can the original author remove this bug in your satisfactory time? How much time you have to spend your own insects? Therefore, the problem of future maintenance is also hesitant to consider whether the developer is considering whether it is used in foreign components. The above is a few reasons why people reinventing the existing solutions are often discarded when they encounter problems. If the conclusion is to use the ready-made solution, then the remaining problem is how to reduce the use of foreign components. The risk is.
Careful selection of foreign components
Here are the conditions I think when choosing foreign components:
Whether the functionality of the component is fully compliant. If you want to modify the program, how much effort is needed. Is there enough technical support, how is the word of mouth. Whether to provide complete raw codes, examples, and explanation files, how is the quality of the program code. There is no difficulty in future updates and maintenance. If you plan to maintain your own maintenance, yourself (or group members) have no ability to maintain. Whether the user interface and the display of the display are easy to change to Chinese.
If you can do some survey assessment in advance, confirm that the quality of the element meets a certain level, I think it will reduce much of many unnecessary trouble.
I think this discussion should be enough about the discussion of the reinvention, let us return to this article to see what is related to the Adapter style when developing applications.
motivation
I don't know if you have touched this situation, the components used in the application, another component after a period of time, for example: originally used the NMFTP component using FASTNET to transfer the file, then use Indy; originally used MSCOMM32 .Ocx's communication program, later to change the VCL component of Delphi .... Something I will encounter when developing applications, please see the example below.
A few years ago, I developed a database application for customers. The program is to store information with a DBASE file. In addition to regular data archives to compress backup, there must be a function similar to the offline database, and some information will be exchanged And compress it to a 1.44MB of magnetophiles to facilitate customers to run the data around, he can work overtime at home, or edit the information on the beach of Hawaii, and the modified information is also compressed. Bring back to the company on the magnetic sheet, after the decompression, the company's database is submitted, so my program has the function of archive compression and decompression.
At first I wrote DOS's batch file to execute pkzip.exe and pkunzip.exe to help me compress files, batch files don't worry, and most of time is working properly, but the disadvantage is that it will open a DOS window when executing The feeling of visual is too bad. If there is no set, the DOS window will not shut down automatically, causing the user's trouble, and the process of compressed files If an error, the user is not aware. So I started thinking about the solution that integrated with the Delphi window application, some commercial components such as Abbrevia, Xceed Zip, VClzip, ..., all the choices, but in the cost of cost, I have Looking for something that is free and easy to use.
Delphi zip
The VCL compressed component that can be found on the Internet is still quite a lot. After a selection, I decided to use the delphi zip to compress the compressed component, because it not only meets the conditions of the original code, but also the function is weak, you can make it with PKZIP Complete compatible compression format, self-decreasing, span disk, wired, auxiliary statement, and support multi-language. It is also very satisfactory after actual use, and the program can display the current progress when performing compression and decompression, and is naturally beautiful than the text mode of the DOS window. This application has always been well working, I have never thought of using other components until the recent developed project must use this compressed component, and I found a regrettable message on the website. Chris Vleghert, which is responsible for maintaining the Delphi Zip project, because of the death of cancer, and I don't know how to connect the latest Beta version of the code, although I know that open the original code strategy has its risk, this is the starting material Not. So, the current maintained work is back to the original author Eric ENGLER. He must picked up the latest to modify from the existing Beta version, which of course has to pay a dumpller. Fortunately, the project, the rebuild, is still very smooth, I boldly use the Beta version in the current project, but this matter has made me alert: if one day this compression element Unable to apply in a new job environment, or a bunch of bugs but no one is maintained, what should I do? Or one day, the boss has bought a commercial component, or the supervisor, demanding that my program has to use another set of components, then how much efforts have to be modified?
So, in order to reduce the risk, it is from the pain that may cause the future maintenance. I decided to prepare for the rain, try the Adapter style.
Delphi Zip's URL is http://www.geocities.com/siliconvalley/neetwork/2114/index.html
Design and practice
[GHJV95] The structural distinguishes of Adapter are two, one is Class Adapter to convert the interface using multiple inheritance; the other is Object Adapter, mainly using the product composite. It is the way to use Object Adapter. I first use the abstract category to comply with your own demand, and then use a CONCRETE CLASS to do this, and the actual part is mostly directly using Delphi. Services of ZIP components, refer to Figure 1:
(Figure 1)
TzipMaster is a category responsible for compression and decompression in the Delphi ZIP component, while Tzipadapter implements the interface defined by TabStractarchiver and encapsulates TzipMaster. Since most of the requirements from Client are just behind the back TzipMaster method, you can imagine that the program code for the Tzipadapter will not be a lot, and the top more is also the process of adding some conversions.
Since I only need to perform simple compression and decompression, some additional functions are not included in TabStractarchiver, such as making self-decreasing and across magnetic disc compression. In order to save things, the names defined in TabStractarchiver are as good as TzipMaster. The ADD in the image is used to compress the file, and "add the file to the file cabinet". If you think that COMPRESS is more appropriate To use your favorite names, use the names of different interfaces, which is the use of Adapter. There is at least the following benefits:
The interface facing the user has become more refreshing, not dozens of properties and methods like the original TzipMaster. The new interface is very easy to learn. If you want to change the Delphi ZIP component in the future, as long as you move in the Tzipadapter category, the user's program is completely free of modification. If you want to support other compressed formats in your app, such as RAR, Arj, ...., etc., as long as you render new categories from TabStractarchiver, in addition to tzipadapter, there may be traradapter, tarjadapter ... However, regardless of how they doctive, the application's writing mode is still constant (multiple), so the application can easily support a variety of compressed formats, more, and then match the Abstract Factory to let the user Perform a dynamically switching to use the compression format.
Let's take a look at this compression interface and act, if you think some content is too cumbersome, you can slightly, some details are only more helpful to people who want to design the same category or have Delphi ZIP.
Tabstractarchiver
This abstract category must contain basic file compression and decompressing features, so named TabStractarchiver. The definition of the category is as follows, the simplicity, I omitted some attributes GET / SET method:
Type
Tabstractarchiver = Class (TOBJECT)
protected
....................
Procedure setArchivename (const value: string); virtual; abstract;
{.... Other Get / SET Method}
public
Constructor create;
Procedure add; virtual; abstract; // Complicates the specified multiple files into a file.
PROCEDURE EXTRACT ;VIRTUAL; Abstract; // Unexpectedly decompressed the specified file.
Property ArchiveName: String Read GetArchiveName Write setArchivename
Property Basedir: String Read GetBasedir Write setBasedir;
Property Specargs: Tstrings Read GetSpecargs;
Property Subfolders: Boolean Readsubfolders;
Property CompressLevel: TcompressLevel ReadcompressLevel Write setcompressLevel;
END;
Among them, the ADD and EXTRACT are performing compression and unpacking actions, and the meaning of each attribute will see the following table: The property name describes the file name of ArchiveName compressed file. Basedir is compressed as the base directory name of the relative path, and decompress the path name as the declined file. SPECARGS wants to compress / decompress the list of files, you can understand that the file name is listed, or you can use the universal character, for example: *. EXE. The empty string represents all files to be processed. Subfolders is compressed by all file directories under the subdirectory. CompressLvel Compression efficiency level.
CompressLvel's type is TcompressLevel, which is another definition, because TzipMaster provides nine compressed methods, I don't think there is not much, and if the subcategory is to do other compressed formats, for example: rar, arj ..., etc., there is no necessarily to have a variety of compression, so simplify the compression level into the following:
TcompressLevel = (Clstore, CLFASTEST, CLFAST, CLNORMAL, CLGOOD, CLBEST);
When the generation of future generations, as long as the GetCompressLevel is done in the setcompressLevel method.
Tzipadapter
Tzipadapter inherits from TabStractarchiver and encapsulates the TzipMaster category, and its category is as follows:
Type
Tzipadapter = Class (Tabstractarchiver)
Private
FZIP: Tzipmaster;
FBasedir: string;
Fsubfolders: boolean;
protected
Function GetArchiveName: string; override;
Procedure setarchiveName (const value: string); override;
{.... Other Get / SET Method}
public
CONSTRUCTOR CRETE; OVERRIDE;
DESTRUCTOR DESTROY; OVERRIDE;
Procedure add; override;
Ovedure
END;
Category Construction Element establishes TzipMaster objects and sets some preset properties, and the deconstruction is responsible for releasing the TzipMaster object:
Constructor tzipadapter.create;
Begin
inherited;
FZIP: = Tzipmaster.create (nil); // Establish an Adaptee item.
// SET Default Properties
SetCompressLevel (CLBest);
Setsubfolders (TRUE);
END;
Destructor Tzipadapter.destroy;
Begin
Freeandnil (FZIP);
inherited;
END;
In addition, since TzipMaster uses the attributes used by compression and decompression, such as rootdir and basedir, one is only compressed, one is extracted, and only a basedir property is defined in the TabStractarchiver, so this attribute must be used at the same time In the compression and decompression, the individual effects have been said in the previous example, and the ROODIR and BASEDIR properties of Tzipmaster must be set when the setBaseDIR method is implemented.
Procedure tzipadapter.setBasedir (const value: string);
Begin
FBasedir: = Value;
Fzip.rootdir: = value;
FZIP.EXTRBASEDIR: = Value;
END;
Similarly, TzipMaster's AddOptions and Extroptions also have options for the same feature, which are addDirNames and extrdirNames options, and only a subfolders property is represented in TabStractarchiver, so SetSubfolders also do additional processing:
Procedure tzipadapter.setsubfolders (const value: boolean);
Begin
Fsubfolders: = Value;
IF fsubfolders kil
Begin
FZip.addOptions: = fzip.addoptions [AddDirms, AddRecurseDirs];
Fzip.extroptions: = fzip.extroptions [extrdirNames];
end
Else Begin
FZip.addoptions: = fzip.addoptions - [addDirNames, addRecurseDirs];
Fzip.extroptions: = fzip.extroptions - [extrdirnames];
END;
END;
The method of compression and decompression is simple, just call the TzipMaster corresponding method:
Procedure tzipadapter.add;
Begin
FZip.Add;
END;
Procedure tzipadapter.extract;
Begin
FZip.extract;
END;
In order to make Delphi Zip display Chinese message, you must also connect Traditional Chinese Message Resource files:
{$ R zipmsgtw.res}
If the new version of Delphi ZIP does not attach the latest traditional Chinese message file, you can also download my website, the URL is http://www.geocities.com/huanlin_tsai/.
The other program code is very simple, and it will not be listed here. If you are interested, you can download the sample form.
The attribute get / set method is defined in the category, you can press Ctrl Shift C to let the IDE help you produce the actual program code of each method, like this: function tzipadapter.setBaseDir (const value: string);
Begin
inherited;
END; but pay attention to these methods have not been actually in the parent category, so you have to go to the IDE to help you generate the inherited line, otherwise 'Abstract Error' will occur when executed.
Non-visual design
Original TzipMaster inherits from Tcomponent, and registers to Delphi IDE, you can easily set up the properties from the component disc onto a TzipMaster component to the Form, and then call the TzipMaster.Add method to perform the action of the compressed file. After now use Tzipadapter, everything is completed, refer to list 1:
Listing 1Procedure TFORM1.BTNCompRESSCLICK (Sender: TOBJECT);
VAR
Arch: Tarchiver; Begin
Arch: = tzipadapter.create;
Try
With Arch Do
Begin
Basedir: = 'C: / Projects';
Specargs.Add ('*. PAS');
ArchiveName: = 'C: /TEST.ZIP';
Subfolders: = TRUE;
ADD;
END;
Arch.free;
Except
Arch.free;
Raise;
END;
END;
This simple example will use all extended files in the C: / Projects / Directory as the files of the .PAS, compressed into C: / Test.zip. It seems that there seems to be convenient to the original visualization, but it can't say trouble, because our Tabstractarchiver defined interface is tailored to yourself, simple and easy to understand, and there are not many properties to set.
The development method of drag and drop components to from From is one of the features of the RAD tool, it is very convenient, but there are also some shortcomings. For example, suppose that one day your colleague wants to modify your program on his computer. If there is no necessary components in advance, a bunch of error messages will appear when the item is turned on, tell you the category Can't find (Class Txxx Not Found) ), Ask you to ignore or Cancel, if you accidentally press the Ignore button, this component is deleted. If you write in a non-visualization, it is to establish an element in the program, and the top is more compilation, just add the path where the component is located, it is ok, even if the component is not installed.
Now suppose a worse case, because a force majeure factor has forced you to use another set of functions, if the component is only one or two times in the program, otherwise you will be on the poorly Huangquan searched all the program code, replaced the components above the Form into new components (modified .dfm file), then modify the code code that is incompatible with new components, and retest the program. This work is both trivial and time consuming, can avoid trying to avoid it, use the Adapter style to reduce this trouble, in this paper, if you really want to replace the compression element, just modify the TzipAdapter category.
Dynamic application
As mentioned earlier, if you match an Abstract Factory to dynamically switch multiple compressed formats during the execution period, in my previous article, "DLL Apps - Design Exchange Modules" also prompts you to use Abstract Factory to improve the original design, but there is no detailed instructions. This time we will take a look at how this is specifically used to produce the Factory category that produces objects.
I intend to support another compressed format in the program: RAR, providing this service to name TRARADAPTER. The Factory category used to establish a compressed article is named TarchiverFactory, so the structure of the previous picture will turn this:
(Figure II)
From the figure, it can be seen that the newly added traradapter is not encapsulated like Tzipadapter, because I intend to use the DOS version of RAR.exe to help me handle compression and unpacking features, so purely to save me writing examples The time of the program code does not have other special reasons. Finally, introduce the practice of TraraDapter, let's take a look at how to write Abstract Factory.
TarchiverFactory
First we must provide a mechanism for a category registration, allowing the user to specify a string to specify the category of the entity (refer to Figure 2), so the user end program only needs to face the abstract category, and can pass through the string when executed To specify awareness category that wants to physically. Obviously this registration mechanism must be able to handle the string and category, we use a TarchiverClassMapping category to provide this service, which records a category name and corresponding category reference state, Reference list 2: List 2Type
// Class Reference Type
Tarchiverclass = Class of Tabstractarchiver;
TARCHIVERCLASSMAPPING = Class (TOBJECT)
Private
Fmappingname: string;
Farchiverclass: Tarchiverclass; TARCHIVERCLASS;
public
Constructor Create (const amappingname: string; aclass: tarchiverclass;
Property mappingname: String Read FmappingName;
Property Archiverclass: TarchiverClass Read FarchiverClass;
END;
IMPLEMetation
Constructor TarchiverclassMapping.create (const amappingname: String)
ACLASS: TARCHIVERCLASS;
Begin
Fmappingname: = AmappingName;
Farchiverclass: = ACLASS;
END;
Then, it is used to build an object: TarchiverFactory, which encapsulates TOBJECTLIST, and uses it to maintain a "string-category reference" series, such as a list 3:
List 3Unit Absarchiver;
Interface
Uses
Windows, Sysutils, Classes, Contnrs
Type
TarchiverFactory = Class (TOBJECT)
Private
Fclasses: TobjectList; // Stores Class-maping list
protected
public
Constructor crete;
DESTRUCTOR DESTROY; OVERRIDE;
Procedure RegisterClass (ACLASS: TARCHIVERCLASS);
Function CreateInstance (const aclassname: string): Tabstractarchiver; overload;
END;
IMPLEMetation
Constructor TarchiverFactory.create;
Begin
FCLASSES: = TOBJECTLIST.CREATE
END;
Destructor TarchiverFactory.DESTROY DESTRUCTORTORY;
Begin
Fclasses.free;
inherited;
END;
Procedure TarchiverFactory.registerClass (ACLASS: TARCHIVERCLASS);
VAR
i: integer;
S1, S2: STRING;
Begin
S1: = aclass.classname;
For i: = 0 to fclasses.count-1 do
Begin
S2: = tarchiverclassmapping (fclasses.items [i]). mappingname; if Sametext (S1, S2) Then // If the category is already registered.
EXIT; // returns directly.
END;
Fclasses.add (TarchiverClassmapping.create (S1, ACLASS));
END;
// Create An Instance of Tabstractarchiver Descendent
Function TarchiverFactory.createInstance
Const AclassName: String): Tabstractarchiver;
VAR
i: integer;
ACM: TARCHIVERCLASSMAPPING;
Begin
For i: = 0 to fclasses.count - 1 do
Begin
ACM: = tarchiverclassmapping (fclasses.Items [i]);
IF Sametext (acm.mappingname, aclassname) THEN
Begin
Result: = ACM.Archiverclass.create;
EXIT;
END;
END;
Raise Exception.createfmt ('<% s> category is not registered', [aclassname]);
END;
Trarchiver
This protagonist is TarchiverFactory, so Trarchiver has everything from Jane, I only have a compressed method, and it is directly called Rar.exe to help me do this, refer to list 4.
Listing 4TYPE
TraraDapter = Class (Tabstractarchiver)
Private
FarchiveName: String;
FBasedir: string;
Fsubfolders: boolean;
FSPECARGS: TSPECARGS: TSPECARGS;
protected
Function GetArchiveName: string; override;
Procedure setarchiveName (const value: string); override;
{.... Other Get / SET Method}
public
CONSTRUCTOR CRETE; OVERRIDE;
DESTRUCTOR DESTROY; OVERRIDE;
Procedure add; override;
Ovedure
END;
IMPLEMentation
{Traradapter}
Constructor traradapter.create;
Begin
FSpeCargs: = TSTRINGLIST.CREATE;
END;
Destructor TraraDapter.destroy;
Begin
FSpeCargs.Free;
inherited;
END;
/ / Call the DOS version of RAR.exe execution compression
Procedure traradapter.add;
VAR
SSWITCHES: STRING
Sfiles: string;
SCMDline: String;
i: integer;
Begin
/ / Establish the parameters required for the command column.
SSWITCHES: = '; // Yes on all queries
IF fsubfolders kil
SSWITCHES: = SSWITCHES '-R'; // Recurse Subdirs
If FBASEDIR <> '' Twitches: = SSWITCHES '-W' FBASEDIR ''; // Work Directory
Sfiles: = '';
For i: = 0 to fspecargs.count-1 do
Sfiles: = sfiles fspecargs [i] '';
SCMDline: = 'RAR A' SSWITCHES ArchiveName sfiles;
Winexec (Pchar (Scmdline), SW_NORMAL);
END;
Procedure traradapter.extract;
Begin
inherited;
ShowMessage ('TraraDapter.extract Not Implement Yet!');
END;
Register to the object factory
Don't forget Tzipadapter and TraraDapter to register to the object factory TarchiverFactory so that the user ends through the string parameter to create a corresponding object, you can register in the unit's Initialization section:
Unit zipadapter;
INITIALIZATION
ArchiverFactory.RegisterClass (Tzipadapter);
====================
Unit rarradapter;
INITIALIZATION
Archiverfactory.registerClass (TraraDapter);
Among them, ArchiverFactory is a well-established Factory object because the entire application used to produce compressed objects only one is enough, so you can solve it with a simple Singleton style, refer to list 5.
Listing 5 // Opened from Absarchiver.Pas Unit
Interface
Tarchiverfactory;
IMPLEMentation
VAR
g_archiverfactory: TarchiverFactory = NIL;
Tarchiverfactory;
Begin
IF g_archiverfactory = nil dam
g_archiverfactory: = TARCHIVERFAACTORY.CREATE;
Result: = g_archiverfactory;
END;
INITIALIZATION
Finalization
IF g_archiverfactory <> nil dam
Freeandnil (g_archiverfactory);
This unique Factory object is not established in the initialization phase of the unit, but the skill of using the delayed construction, when the outside world is required to be used.
So far, we have completed the following categories:
Abstract compression / decompression category Tabstractarchiver (Absarchiver.PAS). Package the Tzipadapter category of the Delphi Zip compression element (zipAdapter.pas). Provides the traradpater category of the RAR compression function (RARADAPTER.PAS). Provides a string with the TarchiverClassMapping category (Absarchiver.pas) corresponding to the category. The object factory for producing compressed objects TarchiverFactory category (Absarchiver.Pas). Now, the outside world can use the string parameter to make the corresponding compressed object, in other words, the user can dynamically switch compression format during execution. Please refer to the program of the list 6, and what is different from the write method of the previous list 1.
Listing 6Procedure TFORM1.BTNCompRESSCLICK (Sender: TOBJECT);
VAR
Arch: Tabstractarchiver;
Sclassname: String;
Begin
// Create Concrete Archiver Class Depending On User's Choice
IF rdozip.checked then
Sclassname: = 'Tzipadapter';
if rdorar.checked then
Sclassname: = 'TRARADAPTER';
Arch: = ArchiverFactory.createInstance (SclassName);
Try
With Arch Do
Begin
Specargs.text: = edspecargs.text;
Basedir: = edbasedir.text;
Archivename: = edarchivename.text;
Subfolders: = chksubfolders.checked;
ADD;
END;
Arch.free;
ShowMessage ('DONE.');
Except
Arch.free;
Raise;
END;
END;
The implementation screen of the program is as follows:
Conclusion
This article first discusses the old problems of reinventing the wheel and what matters should be paid to the use of foreign components, and then illustrate the risk of foreign components, and use the Adapter style to solve similar problems, and finally match the Abstract Factory style Application can handle dynamic needs. For convenience of explanation, the examples used in the text are simplified, and it is not so useful for most people, but it is important to design these categories in:
Interface conversion. Establish an easy maintenance application. Establish a dynamic application.
Design Patterns offers some benefits, but does not guarantee that you can get these benefits, if you use it properly, I believe that the improvement of the quality and maintainability of the program will inevitably help, I hope this article will make you a preliminary preliminary on the Adapter style Awareness. Also don't forget, only through practical practice, it can clearly master the essence of Design Patterns, and become your tools to solve the problem, I wish you a happy learning.
Paradigm
Download the models here: AdapterDemo.zip
Two directories are generated after the compressive file is unwocked, where AdapterDemo1 is version only Tzipadapter, and AdaptRemo2 is a version that can dynamically switch compressed formats. Since AdapterDemo2 requires the DOS version of Rar.exe, this tool program is also attached in the compressed file. The paradigm is written in Delphi 5. If you want to compile these two examples, you must also install Delphi Zip components, you can download: http://www.geocities.com/siliconvalley/neetwork/2114/index. HTML. Remember to copy zip.dll and unzip.dll to the system directory of Windows.
Reference
The delPhi Magazine Issue 74 (October 2001) - The Adaptor Pattern by Peter Hinrichsen. [GHJV95] E. Gamma, R. Helm, R. Johnson, J. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1995. 中文 版: Participation Mode, Ye Bingzhe. Pasheng, 2001.
Reader response
> What is the object factory if you use Builder? > What is the advantages and disadvantages of using delayed constructors?
Although both are also classified in Creational Patterns, the role is similar, but BUILDER is not suitable for replacing Factory in this document. because:
Factory is used to establish an object of the same family, and only one item is established each time, and after the establishment, return to the client to perform other operations. Builder encapsulates a combination of multiple objects, allowing derived Concrete Builders to define the way of combination of objects. Although the BUILDER style can be established by Director, the builder object established is to continue combining the ultimate Product composite object to the client, which is completely different from the latency construct mentioned in the following. The objects established by Factory are in line with the same interface (abstract category), but Builder is built is a category (because the objects established by the preset Builder are different from each other, unified interfaces may not be booked). When the user ends uses a compressed element, it is desirable to be a consistent call mode. Do not use another set of calls because of the compression format, so Factory is more suitable here.
In summary, if you want to establish a composite object, you can use the Builder style, and the purpose of the Factory inside this article is to dynamically switch compressed formats, just establish a single item, so it is suitable for Factory.