Use. NET reflection enhances the extensibility of the object factory

Source: Internet
Author: User
Tags anonymous case statement constructor modify reflection
Object Objects Factory

Object Factory patterns are often used to generate an object from a derived system and return it as an instance of the base class, thus obtaining the interface of the base class and masking the details of the derived class as much as possible in order to take advantage of the object-oriented polymorphism to gain powerful functionality. Typically, an object factory is implemented by using a switch statement based on the type tag, the appropriate type, and then creating an instance of that type and returning it in a factory method.



For example, imagine a graphics system that includes elements such as lines, circles, rectangles, and other elements that have some common operations, such as draw, resize, and so on. Then we may have the following inheritance system:


To be able to differentiate these classes in the object factory, we also need to specify a type tag for each of them. These type tokens can be enumeration, integers, strings, and so on, and can uniquely mark the values of these classes. It looks good to use their class name strings as tags. We can use the object factory below to create a Shape object:



public sealed class Shapefactory

{

Private Shapefactory ()

{

}



public static Baseshape Createshape (String shapeid)

{

Switch (ShapeID)

{

Case "Rectangle":

return new Rectangle ();

Case "Circle":

return new Circle ();

Case "line":

Return to New Line ();

Default

return null;

}

}

}



The only use of shapefacory is to create a shape instance, and we do not want it to be inherited, or to be instantiated, so it is declared as sealed and has a private constructor. When we need to get an instance of a shape, just call the Shapefactory Createshape () method and pass in an appropriate ShapeID string, Createshape () will return the correct shape instance for us.



Enhanced extensibility



Now we have a shape factory, it works well. But the factory has one obvious shortcoming: it is difficult to expand. Whenever a new shape class is added to the system, we have to modify the Createshape () method to add a new case statement to it. This is fine before our product is released, and we have complete control over our code. But when our products are released, users can easily derive their shape classes from Baseshape, but they have difficulty using the Createshape () method to add their shape classes to the system because they cannot modify the implementation of the Createshape () method. So the shape factory also needs some extensibility. But one of the main obstacles to solving this problem is that if you do not use a switch statement, then Createshape () will not be able to know in advance what shape classes exist, and the relationship between type tags and specific classes.



Alexandrescu in his "Modern C + + design" For this problem to give a C + + solution. He uses a std::map in the object factory class to maintain the relationship between the type tag and the type creation method, and adds two interface registers () and unregister () in the Object factory class to register or unregister type tags and type creation methods in this map. For each additional shape class, you need to write an anonymous namespace for this class at the same time, calling the register () method in this space, registering its own type tag and creation method into the object factory.



In C #, we can draw on the Alexandrescu approach, using a Hashtable in the object factory to maintain the relationship between type tags and types, and register using the Register () method. Each shape class must be responsible for its own registration, so we add a registershape () method to each shape class, which calls Shapefactory.register () to register itself. But there are two questions:



1. When should the call to the Registershape () method be carried out?

2. C # does not support anonymous namespaces, so how do you invoke the Registershape () method for each shape class?



For the first question, we have a chance that each shape class must already be registered before the Createshape () method is invoked. It is a good choice to complete the call to Registershape () in a static constructor.



For the second question, we can use the reflection mechanism to first iterate through all the types, find the types derived from Baseshape, and then call their Registershape () methods separately.



According to the above ideas, Shapefactory implementation code is as follows:

public sealed class Shapefactory

{

private static Hashtable _creationmap = null;



Static Shapefactory ()

{

_creationmap = new Hashtable ();



Assembly a = typeof (Shapefactory). module.assembly;

module[] modules = A.getmodules ();

for (int i = 0; i < modules. Length; i++)

{

type[] types = modules[i]. GetTypes ();

for (int j = 0; J < types. Length; J + +)

{

if (!types[j). Equals (typeof (Baseshape))

&& Types[j]. BaseType!= NULL

&& Types[j]. Basetype.equals (typeof (Baseshape))

{

Object obj = types[j]. InvokeMember (NULL,

BindingFlags.DeclaredOnly |

BindingFlags.Public |

BindingFlags.Instance |

Bindingflags.createinstance,

NULL, NULL, NULL);



TYPES[J]. InvokeMember ("Registershape",

BindingFlags.DeclaredOnly |

BindingFlags.Public | BindingFlags.NonPublic |

BindingFlags.Instance | BindingFlags.InvokeMethod,

NULL, obj, NULL);

}

}

}

}



public static void Register (string shapeid, Type shape)

{

if (!_creationmap.containskey (ShapeID))

_creationmap.add (ShapeID, shape);

}



public static Baseshape Createshape (String shapeid)

{

Type shape = (type) _creationmap[shapeid];



if (shape = = null)

return null;



Return (Baseshape) shape. InvokeMember (NULL,

BindingFlags.DeclaredOnly |

BindingFlags.Public |

BindingFlags.Instance | Bindingflags.createinstance,

NULL, NULL, NULL);

}

}



The static constructor executes first before the Createshape () method is invoked for the first time. It uses the reflection mechanism to traverse all types, create an instance of the type derived from Baseshape, and then call its Regisershape () method to register it in Hashtable. When the Createshape () method is invoked, the corresponding type is fetched from the Hashtable according to the incoming ShapeID, and its instance is returned. In this way, we have a shape factory with a certain extensibility.



Summarize



Increasing the reflection mechanism in the object factory can enhance the extensibility of the object factory to some extent. The improved shapefactory no longer has to be modified after each addition of the shape class, as long as the newly added shape class implements the Regisershape () method, it can be registered in the object factory and created correctly. In this way, we can even easily implement plug-in functions for our system. For example, we can specify a plugin directory, traverse this directory, and register the shape class in the factory. Users simply copy their plugins to this directory.



Of course, reflection may not be the best solution to this problem. It needs to traverse all types in the system, and execution is not efficient. Fortunately, a static constructor is only executed once. I hope this paper can play a role in the study. If you have a better plan, you are welcome to communicate with me. My Contact: sam1111@citiz.net



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.