Sign in to follow this  

Pattern/Idiom for Simplifying Interface

This topic is 2099 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm doing some refactoring of a Winforms app, and a particular piece of code doesn't smell right to me. I have a custom control class (call it Canvas), on which a number of Tools can act on it (typical drawing tools such as paint, line, fill, etc.)

Since the Canvas class has grown rather heavy (both in size and public interface), I thought I'd seperate out each tool into a seperate class, which interacts with Canvas directly. Each Tool object is notified of relevent input messages, and communicates back to the Canvas in order to draw, save state for undo, query any necessary data, etc. To do this, each Tool stores a reference to Canvas, and vice versa.

Since Tool needs to communicate with Canvas (and vice versa), it can only do so through public methods on Canvas. Thus, the public Canvas interface isn't getting any smaller/simpler as I'd hoped, although it now has a manageable footprint at least.

To generalize, if I have a class [i]A[/i] which the client (application) interacts with, and a class [i]B[/i] which interacts only with [i]A[/i] (to handle logic related to [i]A[/i]), how do I provide an interface on [i]A [/i]for [i]B[/i] to use that is not exposed to the client?

The obvious answer is to seperate out [i]A [/i]and [i]B[/i] into its own assembly, make [i]B[/i] an [b]internal [/b]class, and add [b]internal [/b]methods to [i]A[/i] for [i]B[/i] to call. I've also thought about hooking into events exposed by [i]B[/i], but I'm not sure this is the ideal use for events.

So I'm wondering if I'm missing something obvious here, a better way, or at least an alternative to seperate assemblies?

Then again, maybe I'm over-thinking things as I sometimes do...

Thanks for any suggestions.

Share this post


Link to post
Share on other sites
A sounds like a facade for a composition of B's. Personally I would ditch A and use the appropriate B at the call sites on the client.

Share this post


Link to post
Share on other sites
[quote name='return0' timestamp='1334531079' post='4931575']
A sounds like a facade for a composition of B's.
[/quote]

Looking up "facade pattern" and reading this here: [url="http://msdn.microsoft.com/en-us/library/orm-9780596527730-01-04.aspx"]http://msdn.microsof...7730-01-04.aspx[/url], it looks like this is basically what I have (where each Tool in my case would be a "subsystem", and the Canvas acting as a facade of sorts). In the example, they indeed use seperate compilation and [b]internal[/b] for limititing visibility, so it appears that is the "correct" way to handle this.

Share this post


Link to post
Share on other sites
The way I tend to do undo/redo is to have methods on the data model perform actions and return an object that is capable of undoing/redoing what was performed. These are then put on to a stack. Extra features such as composing/merging actions based on various predicates (e.g. temporal proximity, homogeneity, etc) can be added on top. In this system, the canvas would not know anything about the tools.

But I've never used Winforms in anger, so I may be missing some specifics that are relevant to your problem.

Share this post


Link to post
Share on other sites
[quote name='edd²' timestamp='1334534179' post='4931590']
The way I tend to do undo/redo is to have methods on the data model perform actions and return an object that is capable of undoing/redoing what was performed. These are then put on to a stack.
[/quote]

Interesting, I hadn't thought of this approach. As it is, I have only a simple single undo/redo toggle implemented, in which I just keep a copy of the last state. In the future, I may come back and add proper undo/redo though.

Also, what both you and return0 seem to be suggesting is working directly through the Tools as the interface, another approach I hadn't considered, and which might work well as far as extending later.

Thanks for the ideas!

Share this post


Link to post
Share on other sites
The command pattern is certainly a starting point, but if naively won't get you very far, unless you have the simplest of applications.

I have a few posts on my blog that describe how you might begin setting up an undo/redo system. It's C++-centric, though most of the ideas/points should translate to .Net.

[url="http://www.mr-edd.co.uk/blog/undo_redo_1_easy_bits"]http://www.mr-edd.co...edo_1_easy_bits[/url]
[url="http://www.mr-edd.co.uk/blog/undo_redo_2_exception_safety"]http://www.mr-edd.co...xception_safety[/url]
[url="http://www.mr-edd.co.uk/blog/undo_redo_3_combining_actions"]http://www.mr-edd.co...mbining_actions[/url]

Maybe I'll finish the series one day... [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]

Share this post


Link to post
Share on other sites
Thanks for links, I'll digest these later when I get some time.

For anyone else reading who might be interested, I also found these:

[url="http://www.codeproject.com/Articles/115978/An-implementation-of-Command-pattern-in-C"]http://www.codeproje...nd-pattern-in-C[/url] looks at one way to implement the command pattern in C#

[url="http://www.codeproject.com/Articles/33371/Multilevel-Undo-and-Redo-Implementation-in-C-Part"]http://www.codeproje...ation-in-C-Part[/url] implements Undo using 3 different methods, including command and memento patterns.

Share this post


Link to post
Share on other sites

This topic is 2099 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this