views:

192

answers:

4

I've had this problem many times before, and I've never had a solution I felt good about.

Let's say I have a Transaction base class and two derived classes AdjustmentTransaction and IssueTransaction.

I have a list of transactions in the UI, and each transaction is of the concrete type AdjustmentTransaction or IssueTransaction.

When I select a transaction, and click an "Edit" button, I need to decide whether to show an AdjustmentTransactionEditorForm or an IssueTransactionEditorForm.

The question is how do I go about doing this in an OO fashion without having to use a switch statement on the type of the selected transaction? The switch statement works but feels kludgy. I feel like I should be able to somehow exploit the parallel inheritance hierarchy between Transactions and TransactionEditors.

I could have an EditorForm property on my Transaction, but that is a horrible mixing of my UI peanut butter with my Model chocolate.

Thanks in advance.

+1  A: 

You need to map your "EditorForm" to a transaction at some point. You have a couple options:

  • A switch statement...like you, I think this stinks, and scales poorly.
  • An abstract "EditorForm" property in base Transaction class, this scales better, but has poor seperation of concerns.
  • A Type -> Form mapper in your frontend. This scales fairly well, and keeps good seperation.

In C#, I'd implement a Type -> Form mapper like this:

Dictionary <Type,Type> typeMapper = new Dictionary<Type,Type>();
typeMapper.Add(typeof(AdjustTransaction), typeof(AdjustTransactionForm));
// etc, in this example, I'm populating it by hand, 
// in real life, I'd use a key/value pair mapping config file, 
// and populate it at runtime.

then, when edit is clicked:

Type formToGet;
if (typeMapper.TryGetValue(CurrentTransaction.GetType(), out formToGet))
{
    Form newForm = (Form)Activator.CreateInstance(formToGet);
}
FlySwat
I think this will work great for me, and the ext. config file suggestion from you and Bill K will really make this nice. Thanks!
James Thigpen
A: 

Do I miss something in the question? I just ask because the obvious OO answer would be: Polymorph

Just execute Transaction.editWindow() (or however you want to call it), and overwrite the method in AdjustmentTransaction and IssueTrasaction with the required functionality. The call to element.editWindow() then opens the right dialog for you.

flolo
He wants to separate the UI from the transaction state class.
FlySwat
+1  A: 

You probably don't want to tie it to the inheritance tree--that will bind you up pretty good later when you get a slight requirements change.

The relationship should be specified somewhere in an external file. Something that describes the relationship:

Editing AdujustmentTransaction = AdjustmentTransactionEditorForm
Editing IssueTransaction = IssueTransactionEditorForm

With a little bit of parsing and some better language than I've used here, this file could become very generalized and reusable--you could reuse forms for different objects if required, or change which form is used to edit an object without too much effort.

(You might want users named "Joe" to use "JoeIssueTransactionEditorForm" instead, this could pretty easily be worked into your "language")

This is essentially Dependency Injection--You can probably use Spring to solve the problem in more general terms.

Bill K
I really like your comment about not tying it to the inh. tree, that makes a lot of sense in the scenario you describe.
James Thigpen
I've had big problems with stuff like that in the past--using reflection to "Figure out" which things go together, but it makes stuff really inflexible. Ruby's "make the common easy and the uncommon possible" fits too--binding classnames and the like breaks the second part of that rule.
Bill K
A: 

An alternative to the Dictionary/Config File approach would be

1) to define a interface for each of the transaction editors.

2) In your EXE or UI assembly have each of the forms register itself with the assembly that creates the individual transaction.

3) The class controlling the registration should be a singleton so you don't have multiple form instances floating around.

3) When a individual transaction is created it pulls out the correct form variable from the registration object and assigns it do an internal variable.

4) When the Edit method is called it just uses the Show method of the internal method to start the chain of calls that will result in the display of that transacton editor.

This eliminates the need for config files and dictionaries. It continues to separate the UI from the object. Plus you don't need any switch statement

The downside is having to write the interface for each every form in addition to the form itself.

If you have a great deal of different types of editors (dozens) then in that case I recommend that you use the Command Pattern

You have a master command that contains the dictonary recommend by Jonathan. That commands in turns will use that dictornary to execute one of a number of other command that calls the correct form with the correct object. The forms continue to be separate from the object themselves. The forms reside in the Command assembly. In addition you don't have to update the EXE to add another editor only the Command assembly. Finally by putting things inside of Command you can implement Undo/Redo a lot easier. (Implement a Unexecute as well as a Execute)

RS Conley