views:

173

answers:

5

I find myself very often creating an object that has no public methods and is self-contained. It typically handles events of arguments passed to its constructor in its private methods and does not raise any events or expose any public methods.

I am calling this type of objects "passive" objects - objects that do not have any public methods defined. All interaction occurs inside them in private methods and events of arguments passed in constructor.

Typically it is some utility class, like one that assures that two forms will be sticked together:

public class StickyForm : IDisposable
{
    private readonly Form form;
    private readonly Form parentForm;

    public StickyForm(Form form, Form parentForm)
    {
        this.form = form;
        this.form.StartPosition = FormStartPosition.Manual;
        this.parentForm = parentForm;

        this.parentForm.LocationChanged += new EventHandler(parent_LocationChanged);
        this.parentForm.SizeChanged += new EventHandler(parent_SizeChanged);

        SetLocation();
    }

    void parent_SizeChanged(object sender, EventArgs e)
    {
        SetLocation();
    }

    void parent_LocationChanged(object sender, EventArgs e)
    {
        SetLocation();
    }

    private void SetLocation()
    {
        //compute location of form based on parent form 
    }

    public void Dispose()
    {
        this.parentForm.SizeChanged -= parent_SizeChanged;
        this.parentForm.LocationChanged -= parent_LocationChanged;
    }
}

But sometimes it is also some kind of controller, providing interaction between two views:

public class BrowseController
{
    private IBrowserView view;
    private IFolderBrowser folderBrowser;

    public BrowseController(IFolderBrowser folderBrowser, IBrowserView view)
    {
        this.view = view;
        this.folderBrowser = folderBrowser;

        this.folderBrowser.NodeOpened += folderBrowser_NodeOpened;
    }

    private void folderBrowser_NodeOpened(object sender, Core.Util.TEventArgs<IPictureList> e)
    {
        this.Browse(e.Value);
    }

    public void Browse(IPictureList content)
    {
        //stripped some code
        AddItemsToView(content);
    }

    private void AddItemsToView(IPictureList browser)
    {
        //call methods on view
    }
}

Are such "passive" objects considered a good design practice?

Is there a better name for this kind of class?

+1  A: 

I don't see anything wrong with that. If it results in clean, readable code, go for it!

Thomas
+1  A: 

I wouldn't call the objects that react to notifications and update their state completely passive.

One other thought, if the objects simply adjust their state to reflect changes in the outside world without providing much of their own, you may slice their "functionality" and put it into other more active "components". There may be not enough reason for these objects to exist.

If this organization however makes you code structure better, clearer and more maintainable, then use it and don't worry about it.

Developer Art
+2  A: 

Seems like fine design to me. I'm not sure about the name passive though. Those classes do seem pretty active. They react to events and do stuff. I would think a class is more passive if you have to call methods on it to get it to do stuff, but normally it wouldn't do anything unless poked.

How about the name "controller". "controller" is the more usual name for a class used in a UI that causes interaction between a view and data, and they quite often don't need to have public methods.

I'm sure there's other ideas for names.

Scott Langham
A: 

Conceptually this appears to be an implementation of strategy pattern. Although in this particular case the reasoning is different from strategy pattern', it still yields very readable and nicely granulated code. Go for it.

UPDATE: to make a little clearer what I mean consider two (or more) classes derived from StickyForm

public class VeryStickyForm : StickyForm
{
//some implementation here
//but interface is completely inherited from StickyForm
}
public class SomewhatStickyForm : StickyForm
{
//some implementation here
//but interface is completely inherited from StickyForm
}

And you decide which one to use dynamically depending on run-time state... you implement a strategy. As I said your solution is conceptually similar to strategy: you select some behavioral aspect of your application that can be well abstracted into policy and move the implementation of the policy into separate class, that does not know about the rest of the application, and your application does not know much about guts of the policy. Even though you do not use it polymorphically, resemblance to strategy is clear.

BostonLogan
Excuse me, but I do not see any sign of strategy pattern in this approach. Could you please elaborate on that?
Marek
Marek@: please see my update to my original post
BostonLogan
This is definitely not a strategy - 1. only one kind of form stickyness is possible 2. algorithm is not switched at runtime. Given your approach, we could call everything you can (possibly) subclass a strategy :)
Marek
+1  A: 

I think that there's one important criteria to meet with this design: can you test it? The designs you have seem to be testable, but you may have to be careful as I can see this leading to some rather untestable code.

In regards to the name, I think this may be an example of the Mediator pattern.

Jason Baker