tags:

views:

89

answers:

3

Hi all:
To put this in concise language...

Aim:
To create a class which can load and save a list of objects to/from a data source.

Current Method:
I have created a class which accepts two delegates as construction parameters:

private class Foo
{
    public delegate List<object> LoadObjectsDelegate();
    public delegate void SaveObjectsDelegate(List<object> data);

    private LoadObjectsDelegate _loadDelegate;
    private SaveObjectsDelegate _saveDelegate;

    public Foo(LoadObjectsDelegate loadDelegate, SaveObjectsDelegate saveDelegate)
    {
        _loadDelegate = loadDelegate;
        _saveDelegate = saveDelegate;
    }

    public List<object> Objects {get; private set;}

    public void Load()
    {
        Objects = _loadDelegate.Invoke();
    }

    public void Save()
    {
        _saveDelegate.Invoke(Objects);
    }
}

i was wondering if there was a cleaner way to do this.

A: 

Well for one thing I'd make it generic (Foo<T>) - your callers can always specify object if they really want, and it means they can use it in a more strongly typed way if necessary.

Currently I'm not sure the class is really adding much value, to be honest. It's really just grouping the three values together - and that's all. If that's what you intended, that's fine... but it feels a bit anaemic to me.

Jon Skeet
John, thanks for your comment. This is indeed correct, but the class has extra functionality to do with those objects <they are not really objects, they are of type T as you have suggested>. It contains functionality for grouping, matching and operating which i have not coppied here in the interest of focusing on the problem at hand :)
TerrorAustralis
+2  A: 

By the looks of it i'd say you're trying to implement the Repository pattern, with some extended functionality. I also see no point in trying to inject the load and save logic, as it's the repository's job to implement them. If the logic of loading and saving objects is the same for all objects in your domain, have it implemented in a base class, and override it in derived classes if needed. This article on SO could give you some ideas on how to deal with this pattern.

devnull
Well done! i was trying to implement a pattern i didnt know existed.. so thanks for informing me of its existence. It was indeed exactly what i was after!
TerrorAustralis
A: 

It is not cleaner, just another approach. If the behaviour which you are specifying in the delegates does not vary too much, consider the Template Pattern.

private abstract class AbstractFoo
{
    public List<object> Objects { get; private set; }

    public List<object> Load();

    public abstract void Save(List<object> data);

    // add common functionality
}


private class ConcreteFoo : AbstractFoo
{
    public override List<object> Load()
    {
        // do specific stuff
    }

    public override void Save(List<object> data)
    {
        // do specific stuff
    }
}

The disadvantage is that you need a class for each specific behaviour. Thus: If the behaviour given by the delegates varies a lot or you need to dynamically load different behaviours, I find your delegate approach is suitable. I usually find the Template Pattern easier to understand and easier to unit test.

You can go one step further: Behavior is specified by inheritance in the Template Pattern. Instead of inheritance you can specify the behaviour by reference if you choose a more abstract approach with an interface:

private interface IRepository
{
    List<object> Load();
    void Save(List<object> data);
}


private class FooBar
{
    private IRepository repository;
    public List<object> Objects { get; private set; }

    public FooBar(IRepository repository)
    {
        this.repository = repository;
    }

    public void Load()
    {
        Objects = repository.Load();
    }

    public void Save()
    {
        repository.Save(Objects);
    }
}

If you need some specific behaviour you need to implement a class derived from IRepository. This approach is even more easier to understand and unit test than the Template Pattern. I often end up replacing the Template Pattern with the latter approach.

Theo Lenndorff