Prototype and various factory models, as well as reflection

Source: Internet
Author: User

Link to this article: prototype mode and various factory modes, as well as reflection

 

The various factory and prototype modes are not described in detail. There is only one small example.

 

The difference between the prototype and the factory mode is that the factory class in the prototype mode maintains the prototype object of a product and returns the clone of the prototype object in the factory method; the factory mode directly returns the new product object.

 

Only the sample code (C #) of the two factories is provided. The product example is given first:

Abstract class abstractproduct: icloneable {<br/> // some methods <br/> public abstract object clone (); <br/>}< br/> class producta: abstractproduct {<br/> // some methods <br/> Public override object clone () {<br/> // clone this object <br/> return NULL; <br/>}< br/> class productb: abstractproduct {<br/> // some methods <br/> Public override object clone () {<br/> // clone this object <br/> return NULL; <br/>}< br/>}

 

Prototype Factory:

Class prototypefactory {<br/> private idictionary <string, abstractproduct> prototypemap; <br/> Public prototypefactory () <br/>: This (new dictionary <string, abstractproduct> () {<br/>}< br/> Public prototypefactory (idictionary <string, abstractproduct> prototypemap) {<br/> This. prototypemap = prototypemap; <br/>}< br/> Public abstractproduct addprototype (string typekey, abstractproduct prototype) {<br /> Abstractproduct oldprototype; <br/> If (! Prototypemap. trygetvalue (typekey, out oldprototype) {<br/> oldprototype = NULL; <br/>}< br/> prototypemap [typekey] = prototype; <br/> return oldprototype; <br/>}< br/> Public abstractproduct removeprototype (string typekey) {<br/> abstractproduct prototype; <br/> If (prototypemap. trygetvalue (typekey, out prototype) {<br/> prototypemap. remove (typekey); <br/>}else {<br/> prototype = NULL; <br/>}< br/> return prototype; <br/>}< br/> Public abstractproduct getinstance (string type) {<br/> return (abstractproduct) This. prototypemap [type]. clone (); <br/>}< br/>}

 

Common simple factory:

Class simplefactory {<br/> Public abstractproduct getinstance (string type) {<br/> If (type = "producta") {<br/> return New producta (); <br/>} else if (type = "productb") {<br/> return New productb (); <br/>} else {<br/> throw new argumentexception ("bad type of product. "); <br/>}< br/>}

 

(For comparison of equality in Java, use: Boolean object. Equals (object ). Java does not overload the "=" operator, so it is not guaranteed that the result of comparing strings with "=" is correct, although it will be correct in most cases .)

 

Through a simple comparison, we can see that the advantages of the prototype model are that the coupling between the prototype factory type and specific products is low. Once the factory class code is compiled, you do not need to change it later. The general factory looks uncomfortable. As long as there are any changes to the specific product system, the factory needs to make relevant adjustments. In this way, the code in both places needs to be maintained at the same time.

 

So are there any improvement measures? Yes, at least in. NET and Java, that is, reflection.

 

We should all know that. NET and Java classes are somewhat different from C ++. c ++ classes only have some basic type information and no metadata. The. NET and Java classes have a large amount of type-related information, which is the so-called metadata (metadata ). What does metadata have? For example, a class has names, namespaces, access permissions, all domain information, all method information, all attribute information, all event information, and all nested class information, A method with a name, a class, an access permission, a returned value type, a parameter table type, or even a method call!

 

The specific procedure is as follows:

A factory Implemented Using Reflection:

Class reflectionfactory {<br/> // cache the constructors <br/> private idictionary <string, constructorinfo> constructormap = new dictionary <string, constructorinfo> (); <br/> Public abstractproduct getinstance (string type) {<br/> constructorinfo constructor; <br/> If (constructormap. trygetvalue (type, out constructor) {<br/> // If constructor already exists <br/> return (abstractproduct) constructor. inv Ke (new object [0]); <br/>}< br/> // else get constructor <br/> string productnamespace = typeof (abstractproduct ). namespace; <br/> type producttype = type. getType (productnamespace + ". "+ type, false); <br/> // producttype will be null if the type not exists. <br/> If (producttype! = NULL & (producttype. issubclassof (typeof (abstractproduct) | producttype. equals (typeof (abstractproduct) {<br/> constructorinfo defaconstructor = producttype. getconstructor (New Type [0]); <br/> If (defaultconstructor = NULL) {<br/> throw new argumentexception ("Params type error. "); <br/>}< br/> // cache it <br/> constructormap [type] = defaultconstructor; <br/> return (abstractproduct) defaultconstructor. invoke (new object [0]); <br/>}else {<br/> throw new argumentexception ("bad type of product. "); <br/>}< br/>}

 

We can see that the common factory implemented by reflection has a low coupling level as the prototype factory, and is lower, because during factory initialization, the prototype factory also needs to initialize its prototype object, and the factory that uses reflection does not need to worry about anything, because it can work only by type information. However, there are two disadvantages: first, at least one constructor of the product series must be identical; otherwise, it cannot be called through reflection; second, the speed must be much lower than the hard-coded common factory model. So when the product type does not need to be changed frequently, we can use the basic factory model.

In this class, the constructor obtained through reflection is cached because the reflection speed is relatively slow compared with the value assignment and method call. Through caching, the number of reflection calls can be reduced. I did a simple test. Under the release setting, 1000000 cyclic calls were made to the Cache version and non-Cache version of the reflection factory respectively. The Cache version was about 4600 + milliseconds, the non-Cache version is about 16000 + milliseconds, with a significant difference. Therefore, do not abuse reflection. Do not use reflection.

There is also a similar solution using reflection, which uses a different method: activator. createinstance (type, object []) caches the product type, which is similar to the sample code above and does not provide specific code.

The comparison shows that the slowest reflection methods used above are: type. GetType (string. Although I don't know how the method is implemented, I guess it may be like this (just a guess): According to the namespace of the complete class name in the parameter, step-by-Step search (I don't know if the type has an index of a certain structure in the Runtime Library); or I can traverse the Assembly to find a matching class. (Alas, I will have the opportunity to read books on the. NET implementation mechanism and the source code of the. NET class library in the future. I should be able to learn more)

 

The advantage of reflection is that it is flexible and even more flexible than dynamic languages. However, in addition to the efficiency problem mentioned earlier (of course, it must be much faster than interpreted language), there is also a very practical problem, reflection cannot help with various checks in the integrated development environment.

 

In most cases, reflection is not required (reflection is mostly used in the tool class). Generally, we use virtual methods and method pointers to implement dynamic calls. So under what circumstances must reflection be used? Let me list the situations I have encountered:

  1. Dynamic Object generation: As we all know, a specific object type must be specified in new. to dynamically obtain a specific object, only reflection is used. The condition is that all related classes must have constructors with the same signature.
  2. Dynamic call of static methods: static methods do not have the virtual feature. If there is a set of inherited classes, each class has a static method that obtains the default value of something, and the method signature is the same. Because static methods cannot use virtual features for dynamic calling, reflection can be used. Of course, the condition is that the method signature must be identical.
  3. I have used a lot of resources. Now I think of this. Please add it ~

Finally, we hope that C ++ can support metadata and reflection in the native way ......

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.