Net-factory Method

Source: Internet
Author: User

 

I. Mode Overview

Perhaps the factory method pattern is the most widely used pattern in the design pattern. In the object-oriented design, object management is the core, and object creation is the first step of Object Management. Object creation is very simple. in C #, you only need to use the new operator to call the object's constructor. However, the time to create an object is very important.

First, from the perspective of object features, the types of abstract relationships, such as interfaces and abstract classes, cannot be created. In other words, the objects we want to create are all related to specific object types. Therefore, the creation of objects involves implementation details in the design, which leads to an enhanced coupling between the creator and the specific creator. For example, if you want to create some graphic objects in a project, such as circle and square. The structure of these objects is as follows:

This structure is very oo-compliant. It abstracts square and circle objects through the ishape interface. According to the principle of polymorphism, we can use ishape in the program to replace the specific square and circle classes, so as to bind the specific object type to the runtime. However, as mentioned above, interface objects cannot be created. Therefore, once an ishape type object is created for a project, it is necessary to create a square or circle object. For example:
Ishape shape = New Square ();

If you are developing a graphical tool, such as square and circle objects, it must be created frequently. We can imagine that the various modules of this project will be filled with the above Code lines, resulting in the failure of the modules to be coupled with the square object, which means that, if we change the created object to circle, we need to modify all modules that call the New Square () operation. This not only increases the workload, but also leads to project non-scalability and the reusability of modules. Abstract ishape of graphic objects does not need to fail.

In the object-oriented design, we often encapsulate the operations that may change. The encapsulated content may be only some behavior, a state, or some responsibilities. In the current case, we need to encapsulate the object creation behavior, which introduces the factory method mode. At this time, the object is the product to be produced by the factory. Since there are two types of products, the corresponding factory should also be two, squarefactory and circlefactory. In the factory method mode, the structure of the factory object should be parallel to the structure of the product and correspond to one of them. Therefore, for the two factories, you also need to abstract a common factory interface ishapefactory for it:

The Code is as follows:
Public interface ishapefactory
{

Ishape createshape ();

}
Public class squarefactory: ishapefactory
{
Public ishape createshape ()
{
Return New Square ();
}
}
Public class circlefactory: ishapefactory
{
Public ishape createshape ()
{
Return new circle ();
}
}

Through the factory method mode, we complete the encapsulation of object creation, move all the previous Code such as ishape shape = New Square () to their respective factory objects, and put it in createshape () method. Shows the entire structure:

Note that the return type of the createshape () method is ishape, which effectively avoids the dependency between the factory object and the specific product object.

Some people may think that although the responsibility for creating an ishape object is transferred to the factory object through the factory method, there are still specific factory class objects in the factory class structure. So far, although we have removed the dependency between the module and the specific shape object, we have increased the dependency on the specific factory object. What benefits does this bring?

Let's analyze the frequency of object creation. For a graphic tool, the creation of ishape objects is undoubtedly frequent, and the greatest possibility is that there may be a need to create an ishape object in each module of this project. However, the factory object is different. We can concentrate on a module to initialize the factory object. When we need the ishape object, we can directly call createshape () of the factory instance () to achieve the goal.

For example, assume that there are three modules in the graphic tool: modulea, moduleb, and modulec. All the three modules need to create square objects, according to the original design scheme, all three modules contain the following code:
Ishape shape = New Square ();

In this case, there are three modules that are dependent on the square object: modulea, moduleb, and modulec. If we need to change the shape object to the Circle type, this change will undoubtedly affect the above three modules. Now, we introduce the factory method mode and add a module named modulefactory. In this module, we create a factory object:
Ishapefactory shapefactory = new squarefactory ();

In this case, the creation of square objects in the original three modules is changed:
Ishape shape = shapefactory. createshape ();

In this case, even if the demand changes, we need to modify the shape object, then we only need to modify the code in the modulefactory module:
Ishapefactory shapefactory = new circlefactory ();

Modulea, moduleb, and modulec modules do not need to be changed at all. Although three factory objects are added to the project and modulefactory is introduced, modulea, moduleb, and modulec are decoupled from specific square objects, in this way, the dependencies between the three modules and product objects are transferred to modulefactory. In this way, the reuse of modules has been greatly improved.

From the above analysis, we can see that the introduction of factory objects is not simply to establish a factory for the product, but to divide the responsibilities of each module and place the creation of factory objects in a proper place. The best solution is to combine the responsibilities of creating factory objects into a module, instead of creating factory objects when you need to create products. An error example is that the factory object is created together with the product object during product creation and distributed in each module:
Ishapefactory shapefactory = new squarefactory ();
Ishape shape = shapefactory. createshape ();

In this way, the introduction of the factory method mode is nothing more than a superfluous image.

Ii. Factory method mode in. NET Framework

The factory method mode is widely used in project design, and is no exception in. NET Framework. For example, to process Web requests in. Net, a base-class webrequest is provided in the framework class library. It can create Web requests based on different protocols by passing in the URI object. For example, if the URI prefix is "https: //" or "http: //", an httpwebrequest object is returned. If it is "file ://", the filewebrequest object is returned. Httpwebrequest and filewebrequest objects are derived classes of webrequest. Webrequest Class Structure

How to Create a webrequest instance? We can directly call the static method create () of this class ():
Webrequest myrequest = webrequest. Create (http://www.cnblogs.com ");

Then we can obtain webresponse Based on the webrequest object:
Webresponse myresponse = myrequest. getresponse ();
......
Myresponse. Close ();

From the code above, the CREATE () static method seems to be an implementation of the simple factory mode. It can judge the webrequest type based on the parameters passed in by the method and create a specific webrequest object, and return this object. The simplest method is to determine the parameter type through the IF/else condition to determine the type of the created object. Obviously, this is not a good method. It directly leads to direct dependency between the specific subclass of webrequest and its static method create (). Once a new webrequest subclass is added, you must modify create () method.

Since object creation is involved, the best way is to use the factory method mode. In. Net, a special factory interface iwebrequestcreate is provided for creating a webrequest object. This interface has only one method, namely, the CREATE () method:
Public interface iwebrequestcreate
{
Webrequest create (URI );
}

The factory mode provides different factory classes for different Web requests, all of which implement the iwebrequestcreate interface. For example, httprequestcreator:
Internal class httprequestcreator: iwebrequestcreate
{
Internal httprequestcreator (){}

Public webrequest create (URI)
{
Return new httpwebrequest (URI );
}
}

Filerequestcreator:
Internal class filewebrequestcreator: iwebrequestcreate
{
Internal filewebrequestcreator (){}

Public webrequest create (URI)
{
Return new filewebrequest (URI );
}
}

These classes all implement the CREATE () method of the iwebrequestcreate interface and return their corresponding webrequest objects, that is, the product to be produced in the factory mode.

In this way, we create a exactly one-to-one factory class structure for the product class:

Note that there is only a dependency between the factory class and the product class between the iwebrequestcreate interface and the abstract class webrequest. This is the essence of abstract programming in OOP.

III. Further Exploration

According to the preceding description, when creating a webrequest object, you must create a factory-class object in the system. As follows:
Iwebrequestcreate webrequestcreate = new httprequestcreator ();

However, unlike general objects, the type of webrequest may change at any time, which leads to frequent changes in the corresponding factory type. If you write the above Code to a dedicated module and modify it for the client, it lacks some flexibility. In addition, it is too troublesome for the customer to create a webrequest object. Because. NET Framework is a class library, the design concept of the class library is to make it easier and easier for users to use the class library. users do not need to care about the internal implementation details. Therefore,. Net performs some processing on the factory method mode. Next, I will conduct an in-depth analysis on the implementation of webreuest Based on. NET.

As mentioned above, webrequest is an abstract class, but it provides a static method, create (), which can create the corresponding webrequest object based on the URI address passed in the method. Its implementation code is as follows:
Public static webrequest create (URI requesturi)
{
If (requesturi = NULL ){
Throw new argumentnullexception ("requesturi ");
}
Return create (requesturi, false );
}

This method actually calls the Private Static Method create () in webrequest ():
Private Static webrequest create (URI requesturi, bool useuribase)
{
String lookupuri;
Webrequestprefixelement current = NULL; // ①
Bool found = false;

If (! Useuribase ){
Lookupuri = requesturi. absoluteuri;
}
Else {
Lookupuri = requesturi. scheme + ':';
}

Int lookuplength = lookupuri. length;
Arraylist prefixlist = prefixlist; // ②

For (INT I = 0; I <prefixlist. Count; I ++)
{
Current = (webrequestprefixelement) prefixlist [I]; // ④

// See if this prefix is short enough.
If (lookuplength> = current. prefix. length)
{
// It is. See if these match.
If (string. Compare (current. prefix, 0, lookupuri, 0, current. prefix. length, true, cultureinfo. invariantculture) = 0)
{
Found = true;
Break;
}
}
}
If (found)
{
Return Current. creator. Create (requesturi); // ③
}

Throw new notsupportedexception (Sr. getstring (sr.net _ unknown_prefix ));
}

Note the lines of code that I have labeled in this method. Line ① defines a webrequestprefixelement object current, line ② defines an arraylist object, and assigns an existing arraylist object prefixlist to it. The Code in line ③ is created using the Creator field of the current object. In general, this method is located in an arraylist and is searched based on the value of the URI parameter. If it is found, related objects are created and returned. Otherwise, an exception is thrown.

Now we need to understand two questions:
1. What is the definition of the webrequestprefixelement class? What type does the Creator field belong?
2. What is the content of prefixlist object storage?

Let's first look at the definition of the webrequestprefixelement class:
Internal class webrequestprefixelement
{
Public String prefix;
Public iwebrequestcreate creator;
Public webrequestprefixelement (string P, iwebrequestcreate C)
{
Prefix = P;
Creator = C;
}
}

Obviously, this class only provides a simple object that associates the URI prefix with the iwebrequestcreate type. The Creator field is of the iwebrequestcreate type. The associated objects of Uri and iwebrequestcreate can be passed in through the webrequestprefixelement constructor.

Therefore, the essence of the current. creator. Create (requesturi) object creation is to call the factory method of the iwebrequestcreate type object to complete the creation of the webrequest object. However, which specific factory class is called? That is, the current field. What is the iwebrequestcreate object?

According to line 4 code, the current value is the iwebrequestcreate object obtained from the prefixlist list. The value of prefixlist is the prefixlist object in this method. Prefixlist is actually a private attribute of the webrequest class:
Private Static arraylist prefixlist
{
Get
{
If (s_prefixlist = NULL)
{
Lock (typeof (webrequest ))
{
If (s_prefixlist = NULL)
{
Globallog. Print ("webrequest: Initialize (): Calling configurationsettings. getconfig ()");
Arraylist prefixlist = (arraylist) configurationsettings. getconfig ("system.net/webrequestmodules ");

If (prefixlist = NULL)
{
Globallog. Print ("webrequest: Initialize (): Creating default settings ");
Httprequestcreator creator = new httprequestcreator ();

// Longest prefixes must be the first
Prefixlist = new arraylist ();
Prefixlist. Add (New webrequestprefixelement ("HTTPS", Creator); // [0]
Prefixlist. Add (New webrequestprefixelement ("HTTP", Creator); // [1]
Prefixlist. Add (New webrequestprefixelement ("file", new filewebrequestcreator (); // [2]
}
S_prefixlist = prefixlist;
}
}
}
Return s_prefixlist;
}
Set
{
S_prefixlist = value;
}
}

In the get accesser of the prefixlist attribute, a series of judgments and initialization work are performed. The most important task is to automatically add three elements inside the get accesser, all of which are webrequestprefixelement objects, through this object, the relationship between Uri and iwebrequestcreate is established in prefixlist:
Prefixlist. Add (New webrequestprefixelement ("HTTPS", Creator); // [0]
Prefixlist. Add (New webrequestprefixelement ("HTTP", Creator); // [1]
Prefixlist. Add (New webrequestprefixelement ("file", new filewebrequestcreator (); // [2]

Of the first two objects, the factory type is httpwebrequestcreator, and the third object is filewebrequestcreator. This is exactly the two factory classes provided by. Net that inherit webrequest.

When you call the static create () method of webrequest, the System Searches the prefixlist for the webrequestprefixelement type object that matches the URI in the prefixlist according to the imported URI object. compare () method ). If this parameter is found, the corresponding factory class is called based on the one-to-one ing relationship, and the corresponding web request instance is created, that is, the ③ line of code in the CREATE () method.

Let's look at the code for creating a webrequest object:
Webrequest myrequest = webrequest. Create (http://www.cnblogs.com ");

According to the previous analysis process, the internal implementation of this line of code encapsulation should be as follows:
1. Pass the string "http://www.cnblogs.com" to the static private method create () of the webrequest class;
2. Assign the prefixlist value of the private attribute of webrequest to the prefixlist object of the local variable in the method. The get accessors of prefixlist are called. The accessor initializes the prefixlist object and adds the default Uri and iwebrequestcreate type values to the prefixlist;
3. parse the passed Uri and get the value "HTTP". The corresponding iwebrequestcreate object is the httpwebrequestcreator object;
4. Call the CREATE () method of the httpwebrequestcreator object, create the httpwebrequest object, and return the result.

The sequence diagram of the steps is as follows:

Now, consider scaling. If the webrequest class is derived from not only the httpwebrequest and filewebrequest subclasses, but also other new subclasses, such as the ftprequest class, whose URI is "ftp ". The corresponding factory class is ftpwebrequestcreator. How should I create it? According to the previous analysis, because no other webrequestprefixelement objects are added to the get accesser of prefixlist, if you enter the URI prefix "ftp", create () you cannot find the appropriate iwebrequestcreate factory object. Do we still need to modify the prefix attribute code in the webrequest class when we extend the new webrequest subclass? If this is the case, the factory classes introduced earlier and a lot of design would seem silly.

Obviously, the designers of. NET Framework cannot make such a ridiculous mistake. In fact, the introduction of the webrequestprefixelement class and the arraylist object prefixlist in the webrequest creation process of. Net has prompted us that the framework has considered the possibility of extension. Because the arraylist object allows us to dynamically add objects. This is exactly the case. In the webrequest class, a public static method registerprefix () for registering webrequestprefixelement is also provided ():
Public static bool registerprefix (string prefix, iwebrequestcreate creator)
{
Bool error = false;
Int I;
Webrequestprefixelement current;

If (prefix = NULL)
{
Throw new argumentnullexception ("prefix ");
}
If (creator = NULL)
{
Throw new argumentnullexception ("creator ");
}

Lock (typeof (webrequest ))
{
Arraylist prefixlist = (arraylist) prefixlist. Clone ();
I = 0;
While (I <prefixlist. Count)
{
Current = (webrequestprefixelement) prefixlist [I];
If (prefix. length> current. prefix. length)
{
// It Is. Break out of the loop here.
Break;
}
If (prefix. Length = current. prefix. length)
{
// They're the same length.
If (string. Compare (current. prefix, prefix, true, cultureinfo. invariantculture) = 0)
{
//... And the strings are identical. This is an error.
Error = true;
Break;
}
}
I ++;
}
If (! Error)
{
Prefixlist. insert (I, new webrequestprefixelement (prefix, Creator ));
Prefixlist = prefixlist;
}
}
Return! Error;
}

As long as the prefix value passed in the parameter is not found in the existing prefixlist, the new prefix value and iwebrequestcreate object will be inserted into the prefixlist. With this method, you can dynamically Add a new factory class. For example:
Webrequest. registerprefix ("ftp", new ftpwebrequestcreator ());
Webrequest ftprequest = webrequest. Create (ftp://www.cnblogs.com ");

With this implementation method, you can solve the coupling between a specific factory class, a specific product class, And the webrequest static method create.

In. NET Framework, the implementation method of webrequest class objects seems complicated, but its essence still belongs to the factory method mode. However, to make the class library easier to use and considering the versatility and scalability, A ing-like webrequestprefixelement class and arraylist object are introduced, and a specific factory class object is set to internal, and packaged into static methods of abstract product base class webrequest. This design method is worth learning when we design our own class library in the factory method mode.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.