|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
Download FactoryMethod_Reflection.zip - 71.1 KB
Introduction
This article attempts to show an usage of the Factory Method design pattern in combination with reflection to achieve extensibility to our application.
In order to illustrate it, we will use an example of creation of accounts for a money management application.
Background
It's not the intention of this article to teach how the Factory Method pattern works, nor the power/features of reflection, instead, we want to demonstrate how to take advantage of them together. If you need to understand any of these two concepts, you may want to search for it first, the Internet is full of materials about it, so you will not have problems to find it! ;)
Problem
Suppose we have to design a money management application, where a user can have different types of accounts to keep track of its money (you can think of Microsoft Money, Quicken, ...). The different types of accounts could be for example (among many others):
- Bank Account; - Credit Card; - Investment Account; - Loan; - Retirement Account; - Stock Options; - Wallet; - Under the Mattress; - etc.
For each of the account types, we have to ask the user for specific informations (maybe even store in a different database table,...depends on your application). For example, you may want to include for a bank acount, information regarding account number, opening date, bank identifier, etc., information that will be pointless for a Wallet account.
So, the problem here is to efficiently ask the user to enter the information for the accounts, and do that in a way we could easily add new account types if needed.
Step 1: Initial Design
Starting our way up to better code, the first approach would be to create an Account class, and add a AccountType property to it. In this way we will have create in this class, properties to all information possible to all kinds of accounts, and when we need to prompt for those informations we do something like the following:
public void PromptForDetails()
{
Account account = new Account();
account.AccountType = comboSelectedType;
if (account.AccountType == AccountTypeEnum.BankAccount)
{
}
else if (account.AccountType == AccountTypeEnum.InvestmentAccount)
{
}
}
With this, we will have to deal with creating and maintaing the enumeration for the account types, filling the combos, etc...
Step 2: Different Classes for Different Account Types
Well, improving our code we now add one different class for each account type, and put a method to prompt for details in each:
public class BankAccount
{
public void PromptForDetails()
{
}
}
public class InvestmentAccount
{
public void PromptForDetails()
{
}
}
Better yet, we create a superclass our account classes could inherit methods from:
public abstract class AccountBase
{
public abstract void PromptForDetails();
}
public class BankAccount : AccountBase
{
public override void PromptForDetails()
{
}
}
public class InvestmentAccount : AccountBase
{
}
But we will still have to prompt for details like this:
public void PromptForDetails()
{
Account account;
if (comboSelectedType == AccountTypeEnum.BankAccount)
{
account = new BankAccount();
}
else if (comboSelectedType == AccountTypeEnum.InvestmentAccount)
{
account = new InvestmentAccount();
}
account.PromptForDetails();
}
Now we could take care of the prompting for account details in each of our classes, and reuse it along the application. But we still have to create the enum, fill the combo and create a if block to verify which type was selected (and all these places will have to be modified if a new account type is added).
Step 3: Now with the Factory Method + Reflection
So, the idea here is to make the program decide which account type we want. That's where the Factory Method design pattern comes in place. The problem we will still have is that we have to make the factory aware of which types of accounts we have available, and its what make difficult for us at the time we want to add more account types in the system, because we will need to go in the factory class and change it apropriately.
The solution is to use reflection to look at our program and inform the factory which account types we have. So first thing, how do we know every account type we have?
To do that we will need to create a property in each account class, to inform how we want the type to be called. For that, let's create the property "AccountType":
public class BankAccount : AccountBase
{
public static String AccountType
{
get { return "Bank Account"; }
}
}
public class InvestmentAccount : AccountBase
{
public static String AccountType
{
get { return "Investment Account"; }
}
}
Now we will use reflection to find every class that inherits from "AccountBase", and will read from it, the property we just create:
public static List AccountTypeList()
{
Assembly currentAssembly = Assembly.GetExecutingAssembly();
List list = new List();
Type[] types;
types = currentAssembly.GetTypes();
foreach (Type currentType in types)
{
if (currentType.BaseType != null && currentType.BaseType.Name.Contains("AccountBase"))
{
try
{
String accountType;
accountType = currentType.GetProperty("AccountType",
BindingFlags.Static | BindingFlags.Public).GetValue(null, null).ToString();
if (!String.IsNullOrEmpty(accountType))
{
list.Add(accountType);
}
}
catch (Exception ex)
{
}
}
}
list.Sort(delegate(string s1, string s2) { return s1.CompareTo(s2); });
return list;
}
Ok, until here we have one benefit already, we could much more easily fill a combo for account type for example, and may no more need enums. Note that the code below to fill a combo, will never have to change, no matter how much new account classes you add:
combo.Items.Clear();
foreach (String s in AccountTypeList())
{
combo.Items.Add(s);
}
Knowing all the account types, and how to present it to user (maybe by a combo like above), we just need to be able to create new instances of a account of the type we want by our factory. Similarly to looking for the list of account types, we create or Factory Method like this:
public static AccountBase FactoryMethod(string accountTypeDesired)
{
Assembly currentAssembly = Assembly.GetExecutingAssembly();
Type[] types;
types = currentAssembly.GetTypes();
foreach (Type currentType in types)
{
if (currentType.BaseType != null && currentType.BaseType.Name.Contains("AccountBase"))
{
try
{
String accountType;
accountType = currentType.GetProperty("AccountType",
BindingFlags.Static | BindingFlags.Public).GetValue(null, null).ToString();
if (accountType.Trim() == accountTypeDesired.Trim())
{
return (AccountBase)Activator.CreateInstance(currentType);
}
}
catch (Exception ex)
{
}
}
}
return null;
}
Well, that's it! Now our code to create and prompt for accounts will simple be (and will never need to change as we add new account types):
String selectedAccountType = comboAccountTypes.Text;
if (!String.IsNullOrEmpty(selectedAccountType))
{
AccountBase account = AccountFactory.FactoryMethod(selectedAccountType);
account.PromptForDetails();
}
Sample Project
We encourage you to download the sample project and see how it's done, see how tha classes are structured, etc. Also, try adding a new account class and see how it works...
Conclusions
In this article we were able to create a extensible application to manage different types of accounts. Each new type of account could be easily added to the system by just adding a new class that subclasses the account base class. In this article, the accounts example was just a good way I find to express the idea behind factory+reflection, but you can use it in several different oportunities in your own projects, and of course, as more 'changeable' the feature you have is, more you will benefit from using the approach present here. Anyway, hope it will be of any use for some of you. Thank you for reading!
| You must Sign In to use this message board. |
|
| | Msgs 1 to 19 of 19 (Total in Forum: 19) (Refresh) | FirstPrevNext |
|
 |
|
|
I'm not familiar with C#, so I'm not sure if this would work, but in C++ (which lacks reflection) you would have each type that wants to be handled by the factory register itself with a global collection object. (In C++ this happens at load time, even before main() is run.) The advantages of this approach are twofold:
1. No need to scan through all classes in the system. 2. If for some reason you needed to subclass BankAccount to create a new class type that should not be handled by the factory (e.g. an abstract class which will be the root of a new sub-hierarchy), this can be done simply by omitting the call to the registration function.
As with your solution, the decision about whether a class should be handled by the factory is made in the class itself with no other code changes required -- in this case, by calling the registration function, rather than by declaring a member with a specific name.
I'm not familiar with "Inversion of Control" either -- perhaps that is what this is?
WTJW
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi, thank you for the post,
What you do is very like IoC. See, I'm big fan of IoC, but there are times when the power of it comes with a price, but we do not need that much power (like in my example here), so why pay the price?! The price is: every time I create a new class, I have to modify the IoC config (registration). The power is: I can do many more things with IoC, like the ones you stated.
Nevertheless, I'm not always looking for that much flexibility like in IoC, in that cases I think Factory+Reflection is a good way to go (but you wouldn't use it every where to replace IoC!).
Also, I noticed that some people are missing the fact that in the factory, the code that gets the classes is just an example...you can do whatever you want in there. You can look for all subclasses of AccountBase, or you can look for all classes in a given namespace, or you can look for all classes srtarting with the letter A, whatever...you can put your own specific rule in there...And as you stated in [2], you could recursively find all classes that directly OR indirectly inherits the AccountBase... Regards, Caio
Intelligence is almost useless for those who have nothing else!
Phone: +55 51 81252.425 Email: caiokf@gmail.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Ah, thanks for the clarification about IoC. If you have to modify some "IoC config" file whenever you add a new class, I certainly agree that that is a big negative factor -- you always have to keep two different things (your primary code file and your "IoC config" file) synchronised, and the whole point of making software maintainable is to avoid that situation.
In contrast, using the C++ solution I was talking about, you never need to modify any "external configuration" files when a class is added. You simply add a line beneath the class declaraction code -- essentially, the C++ code for your new account type looks like this:
class FooAccount : public AccountBase { ... };
REGISTER_CLASS(FooAccount)
REGISTER_CLASS() is just a preprocessor macro that expands to something along the lines of int dummy_var_1234 = AccountFactory::Register(FooAccount, "FooAccount");. dummy_var_1234 is a global variable that exists simply to allow the function AccountFactory::Register() to be called at load time, before main() is executed. A different dummy variable name will be required for each class of course.
All in all, there is no more maintenance effort required than for your approach of declaring a "marker" attribute.
As I said, I'm not sure how much of this will translate to C#, but I imagine it can be done. (For example, the preprocessor macro is just syntactic sugar -- if no preprocessor is available, the expanded code can just be used instead.)
The full approach is described in a rather conversational fashion here: http://www.ddj.com/cpp/184403786[^]. Warning: very heavy C++ content!
Caio Kinzel Filho wrote: Also, I noticed that some people are missing the fact that in the factory, the code that gets the classes is just an example...you can do whatever you want in there.
I understand. However I think that, if the approach I described can be implemented in C#, then it has all the advantages of your approach without the disadvantage of the runtime overhead of scanning through all available classes each time the factory method is called.
Anyway, let me know what you think!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thank you for the C++ insight. Although I used a C/C++ during graduation, I didn't go that far.
I think this is a very good idea, and I think you can do something like that in C#. In fact as ring_0 suggested here, you could create a custom attribute and decorate your class with it, which the factory can look at, instead of the base type. Then it would look a lot like your approach I think...very nice suggestions...
Thank you for the posts! Regards
Intelligence is almost useless for those who have nothing else!
Phone: +55 51 81252.425 Email: caiokf@gmail.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hello, If you boil down the real value of your solution, you would see that you are creating your objects from strings instead of enums. Your target is to make it ever lasting, so that when you add a new substype, your don't need to change your factory.
Well, in my application I needed exactly this. After doing some research I ended up using Spring.Net IoC container. The benefit is, I can create my object depending on my config and also I can have pre-configured object as well. Say, only some of your sub-class don't have a parameter less constructor, then how do you create your reflection based factory? Also, classes have dependencies on other classes that needs care!
Last point, in an application, usually you have some kind of data storage to keep the type values. So, filling a drop down or some other control, is merely a matter of fetching the data from the data store and you don't really need to change the code when you add new rows in the data.
I suggest you take a look at Spring.Net or Unity to learn a better way to achieve what you are willing to. Happy studies!
Had you not been blessed with your eyes, you would miss the colors of life. So, donate posthumous eye and bring color to the lives of the deprived friends.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
"Say, only some of your sub-class don't have a parameter less constructor, then how do you create your reflection based factory?"
Well, if you look at my sample application, you would see that the code in the form that calls the factory to get new objects will never need to change as well. So the problem if you don't have a parameterless constructor would began there. You have to create an if statements, and maintain that code too. Alternatively you can create an adapter or something, but my idea was for using the same kind of objects (say accounts), and you will normally have same class structure, with same base constructors (after all, they all derive from same class).
"Last point, in an application, usually you have some kind of data storage to keep the type values"
I agree. But in that case I believe that when you add another type you will have to mantain the code (create a class), AND adding a value to the data storage. It was not the case my solution wanted to solve. I would use a data storage for let's say, Priorities in a tasklist application, which will not require custom actions, but in the case when the end user will NOT modify the types, and the types WILL require custom actions, I think the factory+reflection would be a reasonable approach.
"I suggest you take a look at Spring.Net or Unity to learn a better way to achieve what you are willing to"
Thank you for your ideas. I think Spring.Net is a very nice framework, in fact I use it in some of my applications! Although I did not use it's IoC. For me, the IoC from Castle Project works better (just think it's a bit easier to use)...
Regards, Caio
Intelligence almost is useless for those who have nothing else!
Phone: +55 51 81252.425 Email: caiokf@gmail.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Caio, Just read your reply. It's absolutely fine that you are creating same type of objects through your factory, in fact this is what factories are supposed to do. But unfortunately, in our world, objects depend on other objects and these dependencies are important. Its the best practice to use dependency injection and inject the dependencies through constructor or properties. And its logical that these dependencies be resolved inside the factory to make it DRY.
I appreciate your solution. Nevertheless, I think the DI/IoC containers are already providing what you are looking for in this article, and in a much comprehensive manner. In fact, these containers must use a somewhat similar approach as yours to achieve the goal. The benefit is, people already put a lot of efforts on these stuffs and its quite smart by now.
Had you not been blessed with your eyes, you would miss the colors of life. So, donate posthumous eye and bring color to the lives of the deprived friends.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Having read some of the other comments, you could also put the bits you want to reflect into a config file that you then read and use the reflection only to instantiate the object. This would reduce the performance hit of searching for the object, even those with Attributes, but starts to enter more into the Dependency Injection arena.
Cheers
life moves pretty fast. If you don't stop and look around once in a while, you could miss it -- Ferris, my hero.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
But having to maintain the config file with the types you want (to use reflection just to instantiate the object) would bring you the same kind of problem we are trying to avoid here. Of course that could give you some more flexibility, but I would not go for inversion of control methods for doing that, at least in projects of the size as the ones I work...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
You could use LinQ for searching for types.
types = (from t in a.GetTypes() where t.BaseType == baseType select t).ToList();
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Yes, good idea! I guess you could make that code a bit more friendly with that...maybe with some yield for returning the values as well...Thanks!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
This is exactly what I've done couple of months ago,however scenario was little different.I had a loads of Items in my combobox and ,rather building a switch or if case for every members, I had used same approach. I have a little question though, what is the reason of creating a Property as
public class BankAccount : AccountBase { public static String AccountType { get { return "Bank Account"; } } //... } Isn't it a better practice to attach a Attribute instead of using property in this case as,
[AccountType("Bank Account")] public class BankAccount : AccountBase { public static String AccountDescription { get { return "Bank Account"; } } //... }
Man having 1 bit brain with parity error
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
Good observation. Yes,you could use an attribute, in fact it will make your code a bit more clear, it's a very good idea. Although in my case, when I used that "factory+reflection" thing, I wanted to access the property (or attribute) from other places other than the factory, so I rather use a property to make a little easier to use in all places...but I agree that using a custom attribute is a good approach.
Thanks, Caio
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi there,
The article is well written, and nicely performed, however I have a couple of questions: 1. Reflection is slow. Especially, if you have large classes, large assemblies, etc. Iterating over all the types in the assembly seems like a huge performance hit. Have you experienced any performance degradation? 2. How are you handling the case where your Account types are not located in the "running assembly"? For example, let assumg that you would like to extend your application with an additional module. You would place the new account type in the new module (assembly). Now, your application needs to iterate over all assemblies, and for each assembly, iterate over all types. This results in loading all those assemblies into memory. Obviously, this affects both performances, and memory usage. Any insights on this?
Thanks, Itay.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi Itay,
Good questions...
1) You're right, you may have little performance degradation, although I haven't done any tests to conclude that. Anyway, if (like me) you're creating business applications, the bottleneck is most likely to be database access, in that case, even if this brings us time increase, it will not be significant at all to the end user. But I'll make some profile of that an post the results when it's done!
2)Well, in that case I think you have some options, but I think the best is to put the Factory class in the same assembly that the rest of the account codes,then the assembly will always be the one you want for that. Also, separating in different assemblies like you propose, can bring you more performance (as concerned in 1) because you will not look in all your project classes, but just in the account related (located in that assembly).
Regards, Caio
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Very intelligent use of the factory and reflection. Now why didnt I think of that? I must have been done the messy factory so so so many times. Thanks a bunch for the flash of light.
|
| Sign In·View Thread·PermaLink | 4.00/5 (2 votes) |
|
|
|
 |
|
|
Thank you, always good to have some feedback! Also, I forgot to put the link for the sample project, now it's there, sorry about that...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
This code comes exactly when I need something like this. Thanks a lot! I'll get in use many of your ideas. 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|