代码之家  ›  专栏  ›  技术社区  ›  TerrorAustralis

课堂设计问题

  •  0
  • TerrorAustralis  · 技术社区  · 14 年前

    用简明的语言表达…

    Aim:
    创建一个类,该类可以在数据源中加载和保存对象列表。

    现行方法:
    我创建了一个类,它接受两个委托作为构造参数:

    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);
        }
    }
    

    我想知道是否有一个更清洁的方法来做这件事。

    3 回复  |  直到 14 年前
        1
  •  2
  •   Community CDub    8 年前

    从外观上看,我想说您正在尝试使用一些扩展功能来实现存储库模式。我还认为尝试注入加载和保存逻辑没有意义,因为实现它们是存储库的工作。如果域中所有对象的加载和保存对象的逻辑相同,请在基类中实现它,并在需要时在派生类中重写它。 This 关于So的文章可以给您一些关于如何处理这种模式的想法。

        2
  •  0
  •   Jon Skeet    14 年前

    好吧,首先,我会让它成为通用的( Foo<T> )-您的呼叫者总是可以指定 object 如果他们真的想要,这意味着他们可以在必要的时候以更强类型的方式使用它。

    老实说,目前我不确定这门课是否真的增加了很多价值。它实际上只是把这三个值组合在一起——仅此而已。如果这是你想要的,那很好…但我觉得有点贫血。

        3
  •  0
  •   Theo Lenndorff    14 年前

    它不干净,只是另一种方法。如果在委托中指定的行为变化不大,请考虑 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
        }
    }
    

    缺点是您需要为每个特定的行为设置一个类。因此:如果代理给出的行为变化很大,或者您需要动态加载不同的行为,我发现您的代理方法是合适的。我通常发现模板模式更容易理解,也更容易进行单元测试。

    您可以更进一步:行为由模板模式中的继承指定。如果选择更抽象的接口方法,则可以通过引用指定行为,而不是继承:

    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);
        }
    }
    

    如果需要某些特定的行为,则需要实现派生自 IRepository . 这种方法比模板模式更容易理解和单元测试。最后我经常用后一种方法替换模板模式。