【问题标题】:Interface With additional property derived from base class具有从基类派生的附加属性的接口
【发布时间】:2014-12-01 09:16:58
【问题描述】:

我尝试将一些操作提取到具有类似这样的一些附加属性的接口中:

基础实体类:

public enum MyClassEnum
{
    classA,
    classB,
    classC
}

public abstract class MyBaseClass
{
    public string entityA { get;set; }
    public int entityB { get; set; }
}

然后我有一些从 MyBaseClass 派生的类:

public class ClassA : MyBaseClass{}

public class ClassB : MyBaseClass
{
    public string AnotherEntity { get; set; }
}

public class ClassC : MyBaseClass
{
    public string AnotherEntity2 { get; set; }
    public string AnotherEntity3 { get; set; }
}

我尝试有一个这样的界面(这是我到目前为止):

public interface IMyClassRepository
{
    void Create(MyBaseClass param);
    void Update(MyBaseClass param);
}

具体的类应该是这样的:

public class ClassBRepository : IMyClassRepository
{
    private readonly BaseRepository _baseRepository;

    public ClassBRepository
    {
        _baseRepository = new BaseRepository();
    }

    public void Create(MyBaseClass param)
    {
        // will use automapper to do the mapping
        var theClassB = MyBaseClass.TranslateTo<ClassB>();

        // How i can design the interface that accept additional Property on class B?

        // last save the operation to DB..
        _baseRepository.Save(theClassB);
    }
}

更新

我将像这样创建IMyClassRepository 使用Factory

public class MyClassFactory
{
    public IMyClassRepository CreateInstance(MyClassEnum param)
    {
        switch(param)
        {
            case MyClassEnum.ClassA
            {
                return new ClassARepository;
            }

            case MyClassEnum.ClassB
            {
                return new ClassBRepository;
            }

            case MyClassEnum.ClassC
            {
                return new ClassCRepository;
            }
        }
    }
}

最终有这样的操作类:

public class ConcreteOperationClass
{
    private IMyClassRepository _myClass;
    public ConcreteOperationClass(MyClassEnum param)
    {
        _myClass = new MyClassFactory().CreateInstance(param);
    }

    public void CreateMyClass(MyBaseClass param, // this should be a parameter class B or Class C needed)
    {
        _myClass.Create(param, // additional property for classB or classC);
    }
}

问题是我如何使用来自ClassBClassC 的附加属性创建IMyClassRepository 的实现?

【问题讨论】:

  • 如果它们完全不同,也许继承不是这里的解决方案。
  • void Create(MyBaseClass param);?你能解释一下这个方法应该做什么吗? (通常Create 会返回它刚刚创建的内容,但在您的设计中并非如此)。
  • @JustinPihony 但它们具有相同的实体和相同的操作。
  • @AlexeiLevenkov 它应该保存一些记录。
  • 如果方法需要 ClassB 的属性,那么它需要一个 ClassB 作为参数。

标签: c# inheritance design-patterns interface abstract-class


【解决方案1】:

如果我理解正确,您是在尝试设计类似于存储库模式的东西吗?如果是这种情况,您可以为所有实体创建一个存储库实现。为此,您需要创建一个与实体的具体实现一起使用的通用接口...

public interface IMyClassRepository<T> where T : MyBaseClass
{
    T Get(int id);
    void Create(T param);
    void Update(T param);
}

然后为每个实体创建此存储库的实现...

public ClassARepo : IMyClassRepository<ClassA>{...}

然后您可以创建一个工厂对象来动态地为这些具体实现提供服务。有点像...

var repository = RepositoryFactory.Resolve<ClassB>(); 
ClassB entity = repository.Get(234);
entity.entityA = "new value";
repository.Update(entity);

如果您使用像 Windsor Castle 这样的 D/I Container,您甚至不必自己实现它,您可以通过配置文件定义实现和服务,甚至可以交换它们而无需重新编译整个应用程序。

【讨论】:

  • @reptildarat 对同一个问题的答案完全相同。每次需要存储库实例时都必须创建工厂对象的实例,这很丑陋。至少你应该让你的 CreateInstance 方法成为一个静态方法......或者让工厂对象成为一个单例对象......或者甚至更好地使用像 Windsor Castle 这样的依赖注入容器来避免那些永远增长的 switch 案例
  • @reptildarat 不用说,拥有enum 来确定要返回哪种实体太没用了。这就是泛型的用途,在运行时推断底层数据类型。您是否想过当您的项目中需要另一个实体时会发生什么?这意味着另一个 enum 值和另一个 swicth...case...这是一个巨大的设计问题,因为自 .Net Framework 2.0 以来您有更好的选择...GENERICS
  • 但是,我需要在 ConcreteOperationClass 上为每个实体创建“创建”,对吧?不仅仅是一种接受所有参数(classA,classB,classC)的方法,这是我的目标。
  • @reptildarat 我不太清楚这意味着什么,但温莎城堡的美妙之处在于你根本不需要创造任何东西。它根据配置文件解决依赖关系
  • 好吧,DI/IoC 是一方面(因为我不能在 ASMX 项目上“轻松”使用它),我明白你的意思。我可以将其提取为通用存储库模式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-17
  • 2023-03-07
  • 2010-12-12
  • 2021-08-29
  • 1970-01-01
相关资源
最近更新 更多