2010-07-07 66 views
7

我定义为IStore的接口,有两个方法:C# - 接口/抽象类 - 确保事件引发的方法

public interface IStore<TEntity> 
{ 
    TEntity Get(object identifier); 
    void Put(TEntity entity); 
} 

我想成为把 的成功引发的事件(参考,放可以存储一个行中的DB或文件系统等文件上...)

因此,实施Istore类型产品的一类看起来有点像这样:

class MyStore : IStore<Product> 
{ 
    public Product Get(object identifier) 
    { 
     //whatever 
    } 

    public void Put(Product entity) 
    { 
     //Store the product in db 
     //RAISE EVENT ON SUCCESS 
    } 
} 

我所追求的是确保IStore的每个实现都引发该事件的方法 - 应该改为抽象类,还是接口?

回答

9

我的建议:

public abstract class Store<TEntity> 
{ 
    public abstract TEntity Get(object identifier); 
    public void Put(TEntity entity) 
    { 
     //Do actions before call 
     InternalPut(entity); 
     //Raise event or other postprocessing 
    } 

    protected abstract void InternalPut(TEntity entity); 
} 

然后覆盖InternalPut在类

+1

这是我的答案。在某种程度上,当你允许方法被覆盖时,你总是依赖于理解合同的人。但是提供这样的框架可以让你对事物允许发生的顺序有一些控制。 – unholysampler 2010-07-07 12:30:30

1

是的,你应该使用抽象类而不是接口。

如果您决定使用实现您的接口的抽象类,它不会阻止其他开发人员实现他们自己的接口版本,最终不会引发事件。即使使用抽象类,也不会强迫其他开发人员使用您的方法,因为他们可能会覆盖它。

我认为最好的方法是使用一个模板方法:

public abstract class AbstractStore<TEntity> 
{ 
    public TEntity Get(object identifier); 
    public sealed void Put(TEntity entity) 
    { 
     if (DoPut(entity)) 
     { 
      // raise event 
     } 
    } 

    protected abstract bool DoPut(TEntity entity); 
} 

真正的商店将必须实现DoPut方法,返回boolean值,指示认沽操作成功。该事件将从Put方法中提出,Put方法是公开可见的。

+0

它不会停止继承类重写行为。没有真正的方法来保证这种行为。 – 2010-07-07 12:26:27

3

确实没有办法确保IStore的每个实现都引发一个事件。您可以拥有一个具有put方法的抽象类,但这并不意味着您可以在完全忽略抽象类方法的抽象类的子类中使用put方法。

最后,鼓励的最好方法是通过抽象类来编写开发人员应该使用的方法。这样一来,他们必须走出自己的路使用它

2

你需要有抽象类实现put方法从你的界面。你还可以添加像PutImpl抽象方法,像这样:

public abstract class MyStoreBase : IStore<TEntity> 
{ 
    public abstract TEntity Get(object identifier); 

    public abstract void PutImpl(TEntity entity); 

    public void Put(TEntity entity) 
    { 
     // Each inheritor will implement this method. 
     PutImpl(entity); 

     // But event is fired in base class. 
     FireEvent(); 
    } 
} 
0

如果你确实需要使用一个接口,那么新PostSharp 2能做方面继承。不幸的是,要获得该功能,您需要至少购买200美元的个人许可证。

有了这样的一个方面,你可以把它放在你的接口声明的方法上,接口的所有实现都会继承它。

0
abstract class Store<TEntity> 
{ 
    public abstract TEntity Get(object identifier); 
    protected abstract void Put(TEntity entity); 
    public void PutBase(TEntity entity) 
    { 
     Put(entity); 
     //Raise event here 
    } 

} 

一些注意事项:我做了保护,所以派生类必须实现它,但客户端代码无法调用它。

0

写一个抽象类来包装类似PutInner的方法绝对是解决这个问题的最好方式,正如其他人已经提出的那样。

我只想补充一点,如果你想为IStore<TEntity>总是引发事件的任何执行时Put叫,我也建议增加表示事件接口本身:

public interface IStore<TEntity> 
{ 
    event EventHandler<EntityEventArgs<TEntity>> EntityAdded; 

    TEntity Get(object identifier); 
    void Put(TEntity entity); 
} 

public EntityEventArgs<TEntity> : EventArgs 
{ 
    public TEntity Entity { get; set; } 
} 

这并未't 强迫执行者做任何事情;但它确实明确地建立了EntityAdded将在成功的Put上筹集的期望。