Introduction

In programming, factories are classes or methods used to create instances of other objects. This is useful when the method calling the factory does not know which is the best object to do what it's needed.

For example, when I hand place a control to edit strings, I use a TextBox. When I hand place a control to edit booleans, I use a checkbox. But, if I do it dynamically, like getting all properties of an object to create the controls, how do I choose the best control to show and edit the value? The answer is simple, I use a factory.

In this case, if I need to support a new data-type, I will add new ifs to the CreateControl method. This can work for a program, but will not work if the factory is in a library called by a program with custom data-types. In this case, the program will need some way to register its editors. Using a dictionary will work but, again, it will not be complete. I could create a control that's able to edit any sub-class of a given class and, so, using a common dictionary will not work. Ok, I have many options here. I could create events, create a specialized dictionary capable of finding base types or even a combination of these. In fact, my solution is the TypeDictionary I created, capable of finding the best control given its data-type, finding its base types and even finding controls for generic types. But, to be honest, this is not the real purpose of the article, so I will move forward.

Advantages

Standardization: If the factory is used everywhere, it is guaranteed that a given data-type will always use the right editor.

Future updates: If, in the future, a new control for a given type is created, a single change in the registered controls will be enough to update the entire system.

Dynamic editors: If you simply want to create a control capable of editing all the properties of any given object, it is really easy to do so when you already have the factory. You simply create a control for each one of the properties in the object.

Maybe there are more advantages, but those three, for me, are enough. But, there is always something that could be lost, so, let's see the disadvantages.

Disadvantages

Lack of customization: When a factory is used, there is always some lack of customization, as the most basic control does not have all the properties of the instantiated controls.

Unalignment: When you first put a control in a window, you know its real size. You can set it to use the most appropriate size needed. But, if in the future a new control, bigger or smaller, is registered, everything can mess up.

So, how do we solve the disadvantages?

The alignment problem is automatically solved by WPF. To be honest, that's why I use WPF. The fact it allow styles and templates is an advantage, but it's not my main goal.

And for the lack of customization, I propose a weak-enforcement and Data-type wrappers.

Weak-enforcement: If a window needs special control placement, special properties set or special events captured, then don't use a factory. The factory is better suited for general purpose content, where it's better to have a fast way to show the content than to have the best way.

Data-type wrappers: In general, people are stuck with basic data-types, many times doing things like this when some validation is needed:

And, not only the Range0_100 and EmailString can already do their validations in the constructor, but a factory can use a better suited control for editing Range0_100 and EmailString than the controls used to edit ints and strings in general.

After some time working with custom data-types for validations and specialized editors, I think everyone will love them. But, even this has some problems. ORMs in general don't support custom data-types. Regarding this, I can only say that my own ORM framework was, in fact, the base of this article. In future, I will re-publish my Database framework, which will use this WpfControlFactory as its heart for Desktop controls.

Attached is a sample that uses the Pfz.WpfControls, which uses the factory model, and a very simple program, without any styles or visual appeal, that simply shows some records, and even has a specialized control for YesNo values, showing a radio-group instead of a combobox.

The TypeDictionary

I already explained some advantages and disadvantages of factories and presented some possible solutions to the disadvantages. Now, I will explain a little about my factory implementation.

My factory is based in the TypeDictionary generic class. This class is, in fact, composed of 6 dictionaries.

One to register values (factories) that only work on exact matches;

One to register values for a class-type or any sub-type;

One to register values for an interface-type or any class that implements such interface;

And the same three dictionaries for generic-type definitions (like List<>).

As the type of the value is generic, such type-dictionary can be used for anything that requires some "class hierarchy" identification but, of course, I use it for factories.

The real important method is: TryFindUp.

The method is a little hard to read, but I will try to explain the steps:

First, we try an exact match.

So, if the type is a generic type definition, we look in the ExactGeneric dictionary. If the type is not a generic type definition, we look into the Exact dictionary.

Obviously, if a match is found we return it. But, if not, we continue.

If the type is an interface, we try to find a value in the interfaces dictionary.

Then, if the type is a class, we try to find a value for InheritableTypes, for the actual type and for each one of it's base types.

Finally, we don't care if the given type was a class or an interface. We extract all the interfaces, try to order them (so, if a class has interface C and D, one that inherits from A and one that inherits from B, we will see C and D first [they will not have a guaranteed order] and A and B after).

And, again, we will try to find a value for each one of the interfaces.

We will only return that no value is found after finishing those steps unsuccessfully.

That's it

I hope this article helps anyone wanting to create a dynamic or general purpose Windows/object editors.

History

16th April, 2010: Initial version

20th April, 2010: More detailed article and using routed-events properly

Share

About the Author

I started to program computers when I was 11 years old, as a hobbist, programming in AMOS Basic and Blitz Basic for Amiga.
At 12 I had my first try with assembler, but it was too difficult at the time. Then, in the same year, I learned C and, after learning C, I was finally able to learn assembler (for Motorola 680x0).
Not sure, but probably between 12 and 13, I started to learn C++. I always programmed "in an object oriented way", but using function pointers instead of virtual methods.

At 15 I started to learn Pascal at school and to use Delphi. At 16 I started my first internship (using Delphi). At 18 I started to work professionally using C++ and since then I've developed my programming skills as a professional developer in C++ and C#, generally creating libraries that help other developers do they work easier, faster and with less errors.

Now I just started working as a Senior Software Engineer at Microsoft.

Comments and Discussions

Of course we could build a type RangedInt0_100, but really what value does that buy us? Why trade the complexity of managing another type in the system for the minimal benefits that a simple check could provide? While I agree there is a object-oriented-benefit to the new type approach, mostly reuse etc., the business case seems to favor the simpler implementation, the simple check; therefore, this level of oop does not seem valuable in a large system. Of course the argument changes significantly if one alters the type in question and the number of system wide uses.

Your thoughts?

You can only be young once. But you can always be immature.
- Dave Barry

In case 1 we can set the invalid value and, later, some process can do the validation using the property attributes. If such process is not invoked, then the validation is simple ignored.

In case 2 the validation will always occur. So we can say it is correct.

In case 3 the validation will always occur, but we have a new type.

But, let's imagine we have 20 properties which the same validation. Which technique is better?
In my opinion, having a type for this.
And, for a simple factory (which does not read the properties attributes) it is also the best solution. The ValueControl, for example, does not need to be bound to a property to work.

Maybe my examples here are not the best ones. In my case, I usually do the same validations "everywhere" for:
Emails, Ranges, Positive values, brazilian numbered documents (CPF, CNPJ, RG). Also, many of these values need specific display formats (like the documents) so, having a type for them only makes everything easier and even avoid common mistakes (for example, in a legacy system, the same type of document was stored with the verification digits in one table, and without them in another table... and those were used in joins).

But I agree. If a simple verification is used only once in the system, it could be easier to use the weak-enforcement I talked about. Hand-code the validation, be it in the object or even in the presentation layer.

And a final note that I forgot to tell before: In the case of ranges, there is a base class Range<>, so I can register control editors for any Range<> for any Range<int> or for a specific range.