Favorites - CodeProject - Use properties (Attributes) and activation mechanisms to implement factory model

xiaoxiao2021-03-06  20

Original http://www.cnblogs.com/wdxinren/archive/2004/11/25/68775.html

Translation: Small New 0574 Review: Allen Lee (Thank you Allen's meticulous audience)

Introduction Introduction

The basic rule for a factory pattern is that the factory should create an instance of an object with a known ancestor, and an unknown implementation behind. Which object to be created is decided by the factory based on the criteria's passed to the factory's method that shall Instantiate the object.

The basic rules of the factory model are that the factory must use a known ancestor (class) to create an instance of an object, and then (for this object) unknown implementation. Which object created is judged by a factory, and its judgment criterion is a method of useful for object instantiation calls in the call party.

I Would Also Like To Share Some Rules That I Usually Follow When I am Writing a factory.

If you need the factory to be able to create more classes than it was originally designed for, you should not have to modify the factory code.The factory should be equally unknowing as the caller about the implementation behind the classes that it can instantiate.The Factory Should Provide A Fixed Mechanism How To Decide Which Class To Instantiate. The Class Itself Should, Which The Factory Should Base It's Decision ON.

I will share with you some rules I follow when you create a factory.

If you want the factory to create more classes than it is originally designed, you should not (arbitrarily) to modify the code of the factory (or change) the factory. The factory should not know if it is used to instantiate the object behind it. Factories must provide a fixed mechanism to determine which class is instantiated. The class itself should provide some information to the factory so that the factory can make judgments based on this information.

One way solve the issues presented in rules 1 and 2 is to let the factory have an internal list of types it could instantiate, and to provide a register mechanism so that it's possible to tell the factory which classes it can instantiate.

A method of solving rules 1 and rule 2 is to allow the factory to have a built-in type list that enumerates the type it can instantiate. In addition, you have to provide a registered mechanism so that which classes tell the factory can be instantiated and possible.

To solve the third rule it would require the classes which the factory can instantiate to override a static abstract method from the ancestor class, since you need information from the class before it's instantiated and you need to override it's behaviour in descendent classes. This is not Possible In .Net Since There is no meaning by Having An Static Abstract Method In. Net, Therefore Weforne: attributes. In order to solve the problem of the third rule, this kind of class is needed, the factory can instantiate These classes cover a static abstraction method of a ancestor, as you need to get information from the class before class instantiation, then override his behavior in its derived class. This is impossible in .NET, because there is no concept of static abstraction methods in .NET, we need to use another way to solve this problem: Features.

In this Article I Will Show You How To Implement A Factory, Which Uses Attributes To Decide Which Class To Instantiate. To Fully Understand This Article You NEED TO HAVE SOME Basic Knowledge About Attributes.

In this article, I will demonstrate how to implement a factory, this factory uses characteristics to determine which class will be instantiated. In order to fully understand this article, you need some basic knowledge about characteristics.

Background

background

Why Do I Think There Three Rules Are So IMPORTANT?

Why do I think these three rules are so important?

Let's say the factory is part of a plug in architecture and could not be modified because it's compiled into a host application or a separate DLL. A third party should easily be able to write a plug in without modifying the factory code. Even if the current Situation is not requiring this at the moment. if you use these three rules at the home system this could Easily Be Accomplished iF The Requirements Changes Later ON

We can think that the factory is part of the plug-in architecture, which cannot be modified because it is compiled into the host program or a separate DLL. The third party can easily write a plugin without modifying the factory code. Even if the current situation is not required. If you use these three rules to develop your system, if you change the demand in the future, you can easily complete it.

I also strongly believe that a class should be an expert on itself. Since a class obviously knows about it's own implementation, why should not the class be a part of the decision making process that decides when to use it? If the class provide the Factory with information to base it's decision on, we could State That The Class IS An Expert on Itself Sincel IT Knows What It Does and when to be used. I also believe that the class is an expert for yourself. Since the class is clearly clear, why not let the class join the decision process to decide when to use himself? If the class provides some information that can make the factory to make a decision, we can think that this class is an expert on itself.

About the code

About code

To Illustrate How To Build Such A Factory, I Have Decided To Use The Following Case:

For example, how to construct such a factory, I decided to use the following situation:

The mission is to create an ASP.NET page which says: "Hello World" when a client is requesting the page The problem is that the page should be available to various types of clients, like HTML browsers, XML Spy and other XML based. Tools, Mobile Phones and Other WML Browsers. The page shop on the page shopted manually by a get from a telnet client.

The task is to create an ASP.NET page, when the client requests this page, "Hello World". The problem is that this page must be available to a wide variety of clients, like HTML browsers, XML SPY, and other XML-based tools, mobile phones, and other WML browsers. Hand manually issuing a GET from a Telnet client to request this page.

Depending on the user agent, the page shop be generated Differently, Either In Html, XML, WML OR in Plain Text for the Telnet Client.

Depending on the user agent, this page should be generated in a different way, either with HTML, XML, WML, or use plain text for a Telnet client.

To Simplify The Demonstration, The Application Will Actually Be An Input Field Where To Enter The "User Agent", And A TextBox to Display The Output.

To simplify this demonstration, this application will actually be a normal Windows application with an input tag to enter the "User Agent" and a text box to display the output.

The Basic IDEA HOW To Solve this task is to have an abstract class Solving the basic idea of ​​this problem is an abstract class

public

Abstract

Class

Responseformatter

{Public abstract string formatResponse (String text);}

which is inherited by several classes and implemented in different ways. For example one class is implemented to format the text using HTML and another class is formatting the text using WML etc. These classes are the classes that the factory is responsible for instantiating.

It can be inherited by some classes and implemented in different ways. For example, a class is implemented using HTML to format text, and another class uses WML to format text, and so on. These classes are those that let the factory responsible for instantiation.

The factory Class Looks Like this:

Factory class is like this:

public

SeaD

Class

ResponseformatterFactory

{Private ArrayList RegisteredImplementations; public ResponseFormatterFactory () {RegisteredImplementations = new ArrayList (); (! ResponseFormatterImpl.IsSubclassOf (typeof (ResponseFormatter)))} public void RegisterResponseFormatter (Type ResponseFormatterImpl) {if throw new ResponseFactoryError ( "Response Formatter must inherit from class Responseformatter "); registeredimplementations.add (responseformatterImpl);} public responseformatter CreateresponseFormatter (String useERAGENT) {}

To make the factory aware of the classes it can instantiate, it has an ArrayList that containins the System.Type for each ResponseFormatter implementation registered. You must therefor register all implementations with the factory using the method RegisterResponseFormatter in order to make it aware of them. The method..

In order to let the factory know that it can instantiate, it has an ArrayList to save system.Type for each registered responseformatter implementation. So you must use the RegisterResponseformatter method to register all the implementations of the factory to enable the factory to know their (saved type). The RegisterResponseformatter method checks if the ResponseFormatter parameter is really a subclass that is inherited by abstract class responseformatter. Each Class That The Factory Should Manage Should Be "Tagged" with one or more use of the one omen 乐 o

Each factory needs to manage the class must use one or more UseRAGENTATTRIBUTE to "tab", just like this:

[AttributeUSAGE (AttributeTargets.class, AllowMultiple

=

True

)]]

public

Class

UseERAGENTATTRIBUTE: Attribute

{Private string UserAgentText; private bool ExactMatch; public UserAgentAttribute (string UserAgentText, bool ExactMatch) {this.UserAgentText = UserAgentText; this.ExactMatch = ExactMatch; (! ExactMatch)} public virtual bool MatchesUserAgent (string UserAgent) {if {return (UserAgent .Tolower (). Indexof (UseRagentText.tolower ())! = -1);} else return useERAGENT.TOLOWER (). Equals (useeragenttext.tolower ());}}

The Attributeusage Attribute Says That Attribute Is Applicable To Classes Only, And It's Okay To Use Several of these Attributes on The Same Class.

AttributeUSAGE features Description This feature is only available for classes, and this feature is not problematic in the same class.

When applying this attribute to a class you must supply two parameters:. UserAgentText and ExactMatch The first parameter is the string that is tested with the useragent you supply when you invoke the factory's CreateResponseFormatter method The next parameter defines how the match should be performed.: Exact Match (True) Or Partial Match (False).

You must provide two parameters when using this feature: UseRagentText and ExactMatch. The first parameter is a string that when you call the factory's CreateresponseFormatter method, it is tested according to the user agent you provide. The second parameter defines what is the match: full match (TRUE) or partial matching (false). . ........................

MatchesuSUSERAGENT methods perform actual tests, according to two parameters, it decides whether this class can fit the specified UserAgent.

Let's have a look at a class thing imports the Abstract Responseformatter

Let's take a look at a class that implements the Responseformatter abstraction class.

[Useragent

"

Mozilla

"

,

False

)]]

public

Class

HTMLRESPONSEFORMATTER: ResponseFormatter

{Public HTMLResponseFormatter () {} public override string FormatResponse (string Text) {System.Text.StringBuilder Response = new System.Text.StringBuilder (); Response.Append ( " "); Response.Append (Text); response.append (" "); return response.toString ();}}

First,..................

First we have a property that this class should be used at this time: the user agent contains (partially matching) strings "mozilla".

The Method FormatResponse is overidden to return The string in the variable text formatted as html.

The FormatResponse method is overwritten to return a string in the Text variable that is formatted using HTML.

Now Let's Check Inside The Method Createresponseformatter in The ResponseFormatterFactory Class:

Now let's check the inside of the Createresponseformatter method in the ResponseformatterFactory class:

public

Responseformatter CreateresponseFormatter

String

UseERAgent)

{// loop thru all registered implementations foreach (Type impl in RegisteredImplementations) {// get attributes for this type object [] attrlist = impl.GetCustomAttributes (true); // loop thru all attributes for this class foreach (object attr in attrlist ) {if (attr is UserAgentAttribute) {// okay, we found an useragent attribute // lets check if it matches our useragent if (((UserAgentAttribute) attr) .MatchesUserAgent (UserAgent)) {// okay, this ResponseFormatter could be // used with the specified UserAgent // created instance and return return (ResponseFormatter) System.Activator.CreateInstance (impl);}}}} // if we got this far, no ResponseFormatter implementation // could be used with this UserAgent throw new ResponseFactoryError ( "Could not find a ResponseFormatter implementation for this UserAgent");} This method consists of two nested loops:. the first loop iterate through all the registered types The second loop iterates through all attributes for the current type.

This method consists of two nesting cycles: the first loop traversed all registration types. The second loop traverses all the characteristics of the current type.

If the attribute is a UserAgentAttribute it calls the attributes MatchesUserAgent method to find out if this class could serve the specified UserAgent. If the MatchesUserAgent returned true we simply instantiate the class behind the type using activation and returns it. If the loop's have finished without finding a Implementation to use, an exception is raised.

If the feature is a userAgentAttribute to invoke the MatchesUseRAgeT method to the feature to find out if this is able to match the specified UserAgent. If MatchesUseRagent returns True We use the activator to simply instantiate the classes behind this type, then return it. If this loop has not found an implementation that can be used, you will throw an exception. Well Let's Put Evesting TOGETHER AND HAVE A LOOK WHERE The FACTORY IS Used. First We'll Create An Instance of The Factory and Register Our IMPLEMENTTION WITH IT.

Ok, let's put all things together to see where the factory is used. First we have created an instance of a factory and use it to register our implementation.

//

CREATE FACTORY

Factory

=

New

ResponseformatterFactory ();

//

Register Implementations

Factory.RegisterResponseformatter

Typeof

(HTMLRESPONSEFORMATTER); Factory.RegisterResponseFormatter

Typeof

(XMLRESPONSEFORMATTER); Factory.RegisterResponseFormatter

Typeof

(TextResponseformatter); Factory.RegisterResponseFormatter

Typeof

WMLRESPONSEFORMATTER);

Next Up is to finally use the factory:

Next, it is also the last step, that is, use the factory:

Private

Void

Btnhello_click

Object

Sender, System.EventArgs E)

{Try {tbResponse.Text = factory.CreateResponseFormatter (cobxUserAgent.Text) .FormatResponse ( "Hello World !!");} catch (ResponseFactoryError error) {MessageBox.Show (error.Message, "Error");}}

And That's it!

This is it!

Points of interest

interesting place

Since I am AN old delphi coder I am Used to the Fact That's Possible To Utilize Static Abstract Methods, or as it's called in

Delphi: an abstract class function When I found out that this was not possible in .NET i was very depressed for a couple of days, until I stumbled upon attributes Attributes is a very powerful tool for the programmer and could in a way.! Mimic The Behaviour of Abstract Static Methods Since You Can Derive Attributes As Well.

Because I am a programmer who uses Delphi for a long time, I am used to it likely to use Static Abstract Methods, in Delphi it is called: An Abstract Class Function. When I found it in .NET, I lost a few days until I found the characteristics! Features For programmers, it is a powerful tool that can use a method to simulate the abstract static method, because you can also inherit characteristics. Original link: http://www.codeproject.com/csharp/factorywithattributes.asp

Original author:

John Gunnarsson

public

Abstract

Class

Responseformatter

{Public abstract string formatResponse (String text);}

which is inherited by several classes and implemented in different ways. For example one class is implemented to format the text using HTML and another class is formatting the text using WML etc. These classes are the classes that the factory is responsible for instantiating.

It can be inherited by some classes and implemented in different ways. For example, a class is implemented using HTML to format text, and another class uses WML to format text, and so on. These classes are those that let the factory responsible for instantiation.

The factory Class Looks Like this:

Factory class is like this:

public

SeaD

Class

ResponseformatterFactory

{Private ArrayList RegisteredImplementations; public ResponseFormatterFactory () {RegisteredImplementations = new ArrayList (); (! ResponseFormatterImpl.IsSubclassOf (typeof (ResponseFormatter)))} public void RegisterResponseFormatter (Type ResponseFormatterImpl) {if throw new ResponseFactoryError ( "Response Formatter must inherit from class Responseformatter "); registeredimplementations.add (responseformatterImpl);} public responseformatter CreateresponseFormatter (String useERAGENT) {}

To make the factory aware of the classes it can instantiate, it has an ArrayList that containins the System.Type for each ResponseFormatter implementation registered. You must therefor register all implementations with the factory using the method RegisterResponseFormatter in order to make it aware of them. the method RegisterResponseFormatter checks that the ResponseFormatter parameter actually is a type subclassed from the abstract class ResponseFormatter. in order to make the plant know that it can instantiate the class with an ArrayList to implement System.Type to save ResponseFormatter each registered. So you must use the RegisterResponseformatter method to register all the implementations of the factory to enable the factory to know their (saved type). The RegisterResponseformatter method checks if the ResponseFormatter parameter is really a subclass that is inherited by abstract class responseformatter.

Each Class That The Factory Should Manage Should Be "Tagged" with one or more use of the one omen 乐 o

Each factory needs to manage the class must use one or more UseRAGENTATTRIBUTE to "tab", just like this:

[AttributeUSAGE (AttributeTargets.class, AllowMultiple

=

True

)]]

public

Class

UseERAGENTATTRIBUTE: Attribute

{Private string UserAgentText; private bool ExactMatch; public UserAgentAttribute (string UserAgentText, bool ExactMatch) {this.UserAgentText = UserAgentText; this.ExactMatch = ExactMatch; (! ExactMatch)} public virtual bool MatchesUserAgent (string UserAgent) {if {return (UserAgent .Tolower (). Indexof (UseRagentText.tolower ())! = -1);} else return useERAGENT.TOLOWER (). Equals (useeragenttext.tolower ());}}

The Attributeusage Attribute Says That Attribute Is Applicable To Classes Only, And It's Okay To Use Several of these Attributes on The Same Class.

AttributeUSAGE features Description This feature is only available for classes, and this feature is not problematic in the same class.

When applying this attribute to a class you must supply two parameters:. UserAgentText and ExactMatch The first parameter is the string that is tested with the useragent you supply when you invoke the factory's CreateResponseFormatter method The next parameter defines how the match should be performed.: Exact Match (True) Or Partial Match (False). You must provide two parameters when you use this feature: UseERAGENTTEXT and EXACTMATCH. The first parameter is a string that when you call the factory's CreateresponseFormatter method, it is tested according to the user agent you provide. The second parameter defines what is the match: full match (TRUE) or partial matching (false).

. ........................

MatchesuSUSERAGENT methods perform actual tests, according to two parameters, it decides whether this class can fit the specified UserAgent.

Let's have a look at a class thing imports the Abstract Responseformatter

Let's take a look at a class that implements the Responseformatter abstraction class.

[Useragent

"

Mozilla

"

,

False

)]]

public

Class

HTMLRESPONSEFORMATTER: ResponseFormatter

{Public HTMLResponseFormatter () {} public override string FormatResponse (string Text) {System.Text.StringBuilder Response = new System.Text.StringBuilder (); Response.Append ( " "); Response.Append (Text); response.append (" "); return response.toString ();}}

First,..................

First we have a property that this class should be used at this time: the user agent contains (partially matching) strings "mozilla".

The Method FormatResponse is overidden to return The string in the variable text formatted as html.

The FormatResponse method is overwritten to return a string in the Text variable that is formatted using HTML. Now Let's Check Inside The Method Createresponseformatter in The ResponseFormatterFactory Class:

Now let's check the inside of the Createresponseformatter method in the ResponseformatterFactory class:

public

Responseformatter CreateresponseFormatter

String

UseERAgent)

{// loop thru all registered implementations foreach (Type impl in RegisteredImplementations) {// get attributes for this type object [] attrlist = impl.GetCustomAttributes (true); // loop thru all attributes for this class foreach (object attr in attrlist ) {if (attr is UserAgentAttribute) {// okay, we found an useragent attribute // lets check if it matches our useragent if (((UserAgentAttribute) attr) .MatchesUserAgent (UserAgent)) {// okay, this ResponseFormatter could be // used with the specified UserAgent // created instance and return return (ResponseFormatter) System.Activator.CreateInstance (impl);}}}} // if we got this far, no ResponseFormatter implementation // could be used with this UserAgent throw New ResponseFactoryError ("Could Not Find A Responseformatter Implementation for this Userature");

This Method Consists of Two Nested Loops: The First Loop Iterate Through All The Registered Types. The Second Loop Itreates Through Type.

This method consists of two nesting cycles: the first loop traversed all registration types. The second loop traverses all the characteristics of the current type.

If the attribute is a UserAgentAttribute it calls the attributes MatchesUserAgent method to find out if this class could serve the specified UserAgent. If the MatchesUserAgent returned true we simply instantiate the class behind the type using activation and returns it. If the loop's have finished without finding a Implementation to use, an exception is raised. If the feature is a MatchesUseRAgent method that calls the feature to find this, you can match the specified useERAGENT. If MatchesUseRagent returns True We use the activator to simply instantiate the classes behind this type, then return it. If this loop has not found an implementation that can be used, you will throw an exception.

Well Let's Put Evesting TOGETHER AND HAVE A LOOK WHERE The FACTORY IS Used. First We'll Create An Instance of The Factory and Register Our IMPLEMENTTION WITH IT.

Ok, let's put all things together to see where the factory is used. First we have created an instance of a factory and use it to register our implementation.

//

CREATE FACTORY

Factory

=

New

ResponseformatterFactory ();

//

Register Implementations

Factory.RegisterResponseformatter

Typeof

(HTMLRESPONSEFORMATTER); Factory.RegisterResponseFormatter

Typeof

(XMLRESPONSEFORMATTER); Factory.RegisterResponseFormatter

Typeof

(TextResponseformatter); Factory.RegisterResponseFormatter

Typeof

WMLRESPONSEFORMATTER);

Next Up is to finally use the factory:

Next, it is also the last step, that is, use the factory:

Private

Void

Btnhello_click

Object

Sender, System.EventArgs E)

{Try {tbResponse.Text = factory.CreateResponseFormatter (cobxUserAgent.Text) .FormatResponse ( "Hello World !!");} catch (ResponseFactoryError error) {MessageBox.Show (error.Message, "Error");}}

And That's it!

This is it!

Points of interest

interesting place

Since I am an old Delphi coder I am used to the fact that it's possible to utilize static abstract methods, or as it's called inDelphi:. An abstract class function When I found out that this was not possible in .NET i was very depressed for a couple of days, until I stumbled upon attributes! Attributes is a very powerful tool for the programmer and could in a way mimic the behaviour of abstract static methods since you can derive attributes as well.

Because I am a programmer who uses Delphi for a long time, I am used to it likely to use Static Abstract Methods, in Delphi it is called: An Abstract Class Function. When I found it in .NET, I lost a few days until I found the characteristics! Features For programmers, it is a powerful tool that can use a method to simulate the abstract static method, because you can also inherit characteristics.

Original link: http://www.codeproject.com/csharp/factorywithattributes.asp

Original author:

John Gunnarsson

public

Abstract

Class

Responseformatter

{Public abstract string formatResponse (String text);}

which is inherited by several classes and implemented in different ways. For example one class is implemented to format the text using HTML and another class is formatting the text using WML etc. These classes are the classes that the factory is responsible for instantiating.

It can be inherited by some classes and implemented in different ways. For example, a class is implemented using HTML to format text, and another class uses WML to format text, and so on. These classes are those that let the factory responsible for instantiation.

The factory Class Looks Like this:

Factory class is like this:

public

SeaD

Class

ResponseformatterFactory

{Private ArrayList RegisteredImplementations; public ResponseFormatterFactory () {RegisteredImplementations = new ArrayList (); (! ResponseFormatterImpl.IsSubclassOf (typeof (ResponseFormatter)))} public void RegisterResponseFormatter (Type ResponseFormatterImpl) {if throw new ResponseFactoryError ( "Response Formatter must inherit from class ResponseFormatter "); RegisteredImplementations.Add (ResponseFormatterImpl);} public ResponseFormatter CreateResponseFormatter (string UserAgent) {}} To make the factory aware of the classes it can instantiate, it has an ArrayList that containins the System.Type for each ResponseFormatter implementation registered. You must therefor register all implementations with the factory using the method RegisterResponseFormatter in order to make it aware of them. The method RegisterResponseFormatter checks that the ResponseFormatter parameter actually is a type subclassed From the Abstract Class Responseformatter.

In order to let the factory know that it can instantiate, it has an ArrayList to save system.Type for each registered responseformatter implementation. So you must use the RegisterResponseformatter method to register all the implementations of the factory to enable the factory to know their (saved type). The RegisterResponseformatter method checks if the ResponseFormatter parameter is really a subclass that is inherited by abstract class responseformatter.

Each Class That The Factory Should Manage Should Be "Tagged" with one or more use of the one omen 乐 o

Each factory needs to manage the class must use one or more UseRAGENTATTRIBUTE to "tab", just like this:

[AttributeUSAGE (AttributeTargets.class, AllowMultiple

=

True

)]]

public

Class

UseERAGENTATTRIBUTE: Attribute

{Private string UserAgentText; private bool ExactMatch; public UserAgentAttribute (string UserAgentText, bool ExactMatch) {this.UserAgentText = UserAgentText; this.ExactMatch = ExactMatch; (! ExactMatch)} public virtual bool MatchesUserAgent (string UserAgent) {if {return (UserAgent .! .ToLower () IndexOf (UserAgentText.ToLower ()) = -1);} else return UserAgent.ToLower () Equals (UserAgentText.ToLower (.));}} The AttributeUsage attribute says that this attribute is applicable to classes Only, And It's Okay To Use Several of these Attributes on the Same Class.

AttributeUSAGE features Description This feature is only available for classes, and this feature is not problematic in the same class.

When applying this attribute to a class you must supply two parameters:. UserAgentText and ExactMatch The first parameter is the string that is tested with the useragent you supply when you invoke the factory's CreateResponseFormatter method The next parameter defines how the match should be performed.: Exact Match (True) Or Partial Match (False).

You must provide two parameters when using this feature: UseRagentText and ExactMatch. The first parameter is a string that when you call the factory's CreateresponseFormatter method, it is tested according to the user agent you provide. The second parameter defines what is the match: full match (TRUE) or partial matching (false).

. ........................

MatchesuSUSERAGENT methods perform actual tests, according to two parameters, it decides whether this class can fit the specified UserAgent.

Let's have a look at a class thing imports the Abstract Responseformatter

Let's take a look at a class that implements the Responseformatter abstraction class.

[Useragent

"

Mozilla

"

,

False

)]]

public

Class

HTMLRESPONSEFORMATTER: ResponseFormatter

{Public HTMLResponseFormatter () {} public override string FormatResponse (string Text) {System.Text.StringBuilder Response = new System.Text.StringBuilder (); Response.Append ( " "); Response.Append (Text); Response.Append (" "); return response.tostring ();}} first of all we have the attribute which say this class shouth be used when the useERAGENT CONTAINS (Partial Matching) The string "mozilla".

First we have a property that this class should be used at this time: the user agent contains (partially matching) strings "mozilla".

The Method FormatResponse is overidden to return The string in the variable text formatted as html.

The FormatResponse method is overwritten to return a string in the Text variable that is formatted using HTML.

Now Let's Check Inside The Method Createresponseformatter in The ResponseFormatterFactory Class:

Now let's check the inside of the Createresponseformatter method in the ResponseformatterFactory class:

public

Responseformatter CreateresponseFormatter

String

UseERAgent)

{// loop thru all registered implementations foreach (Type impl in RegisteredImplementations) {// get attributes for this type object [] attrlist = impl.GetCustomAttributes (true); // loop thru all attributes for this class foreach (object attr in attrlist ) {if (attr is UserAgentAttribute) {// okay, we found an useragent attribute // lets check if it matches our useragent if (((UserAgentAttribute) attr) .MatchesUserAgent (UserAgent)) {// okay, this ResponseFormatter could be // used with the specified UserAgent // created instance and return return (ResponseFormatter) System.Activator.CreateInstance (impl);}}}} // if we got this far, no ResponseFormatter implementation // could be used with this UserAgent throw new ResponseFactoryError ( "Could not find a ResponseFormatter implementation for this UserAgent");} This method consists of two nested loops:. the first loop iterate through all the registered types The second loop iterates through all attributes for the current type.

This method consists of two nesting cycles: the first loop traversed all registration types. The second loop traverses all the characteristics of the current type.

If the attribute is a UserAgentAttribute it calls the attributes MatchesUserAgent method to find out if this class could serve the specified UserAgent. If the MatchesUserAgent returned true we simply instantiate the class behind the type using activation and returns it. If the loop's have finished without finding a Implementation to use, an exception is raised.

If the feature is a userAgentAttribute to invoke the MatchesUseRAgeT method to the feature to find out if this is able to match the specified UserAgent. If MatchesUseRagent returns True We use the activator to simply instantiate the classes behind this type, then return it. If this loop has not found an implementation that can be used, you will throw an exception. Well Let's Put Evesting TOGETHER AND HAVE A LOOK WHERE The FACTORY IS Used. First We'll Create An Instance of The Factory and Register Our IMPLEMENTTION WITH IT.

Ok, let's put all things together to see where the factory is used. First we have created an instance of a factory and use it to register our implementation.

//

CREATE FACTORY

Factory

=

New

ResponseformatterFactory ();

//

Register Implementations

Factory.RegisterResponseformatter

Typeof

(HTMLRESPONSEFORMATTER); Factory.RegisterResponseFormatter

Typeof

(XMLRESPONSEFORMATTER); Factory.RegisterResponseFormatter

Typeof

(TextResponseformatter); Factory.RegisterResponseFormatter

Typeof

WMLRESPONSEFORMATTER);

Next Up is to finally use the factory:

Next, it is also the last step, that is, use the factory:

Private

Void

Btnhello_click

Object

Sender, System.EventArgs E)

{Try {tbResponse.Text = factory.CreateResponseFormatter (cobxUserAgent.Text) .FormatResponse ( "Hello World !!");} catch (ResponseFactoryError error) {MessageBox.Show (error.Message, "Error");}}

And That's it!

This is it!

Points of interest

interesting place

Since I am AN old delphi coder I am Used to the Fact That's Possible To Utilize Static Abstract Methods, or as it's called in

Delphi: an abstract class function When I found out that this was not possible in .NET i was very depressed for a couple of days, until I stumbled upon attributes Attributes is a very powerful tool for the programmer and could in a way.! Mimic The Behaviour of Abstract Static Methods Since You Can Derive Attributes As Well.

Because I am a programmer who uses Delphi for a long time, I am used to it likely to use Static Abstract Methods, in Delphi it is called: An Abstract Class Function. When I found it in .NET, I lost a few days until I found the characteristics! Features For programmers, it is a powerful tool that can use a method to simulate the abstract static method, because you can also inherit characteristics. Original link: http://www.codeproject.com/csharp/factorywithattributes.asp

Original author:

John Gunnarsson

转载请注明原文地址:https://www.9cbs.com/read-43345.html

New Post(0)