每个实体实现接口?

时间:2016-11-03 10:04:51

标签: c# interface architecture entity

目前,我正致力于应用程序架构,我的项目中有许多实体,即学生师范大学,我想知道所有实体都必须实现接口是一个好习惯。这有助于我依赖注入吗?从架构的角度来看,最佳实践是什么。

 public interface IMyEntity
    {
          //an empty interface
    }
public class Student:IMyEntity
{

}
public class Teacher:IMyEntity
{

}

//嗨我可以处理实现IMyEntity的每个对象

void Display(IMyEntity entity) //this function can be in some class
{
    // if IMyEntity is teacher behave like a teacher
    // if IMyEntity is student behave like sutdent
}

我知道界面是合同,但从架构的角度来看这是最佳实践吗?我知道我的IMyEntity接口是空的。

4 个答案:

答案 0 :(得分:0)

不一定。如果在这种情况下,学生和教师有一些共同的功能,那么共享界面将是一种方法。

public void Display(IUniPerson person)
{
    var name = person.Name; // Everyone, student or teacher, has a name
    ...
}

但是,您给出的示例似乎表明情况并非如此,并且Display方法将尝试以不同的方式处理传入的IMyEntity实例,具体取决于它的类型。在这种情况下,使用具有不同参数的2种显示方法可能会更好。

public void Display(ITeacher teacher) { // teacher processing }
public void Display(IStudent student) { // student processing }

tl:dr version:如果这些类有意义地实现相关的方法和功能,而不是仅仅作为一揽子规则,则实现跨多个类的接口。

答案 1 :(得分:0)

我认为解耦2个或更多类在开发方面是一个很好的品味,从长远来看它确实有助于维护代码

考虑以下情况:

static void Main(string[] args)
{
    var objA = new A();
    var objB = new B(objA);
}

public class A {}

public class B 
{
  public B(A obj)
  {
    //Logic Here
  }
}

这段代码的问题在于它是强耦合的,B类需要A类才能实例化并且做它的业务。

如果你确定B永远不会有一些剧烈的变化,这不是问题。

现在,如果我们想要解耦它,我们可以实现像

这样的接口的第一次改进
static void Main(string[] args)
{
    var objA = new A();
    var objB = new B(objA);
}

public interface IA()
{
    //TODO
}

public class A : IA {}

public class B 
{
  public B(IA obj)
  {
    //Logic Here
  }
}

在Main中,我们仍然有一个couplation问题看起来好多了,所以此时我们必须使用像Ninject这样的IOC和我们的代码实现依赖注入会是这样的:

static void Main(string[] args)
{
    var objB = new B();
}

public interface IA()
{
    //TODO
}

public class A : IA {}

public class B 
{
  public B(IA obj)
  {
    //Logic Here
  }
}

是的,看起来不错。我们已经完全删除了couplation 问题,如果将来我们只需要拿A,删除它并替换它,那就更容易了。

显然过度使用这是一种不好的做法而且我相信DI必须在经过精心策划以避免无用的实施后才能使用。

例如,如果我有一个具有一些基本操作的C类,并且我确信它永远不会改变或者有一些需要更新的剧烈需要我可以避免DI。

那么你必须在项目的每个模型上实现接口吗?

我认为你的项目中的每个模型都不需要实现一个界面或DI,只需要考虑它并看到它可能有用的地方以及它过度使用的地方

答案 2 :(得分:0)

是的,这样做,这是最好的做法。这为您提供了多态性的优势。你应该在当前环境中以更好的方式做到这一点并不好,因为Student不是Teacher。如果要共享通用接口,则应将其定义为:IUniversityMember。这里有一个例子,我认为这个例子可以说清楚。

public interface IUniversityMember
{
   //... here common fields between `Teacher` and `Student`
   string Name{ get; set;}
   string Gender { get; set;}
}

//after that

public interface IStudent
{
    int GetGPA();
    int CreditsToPass {get; private set;}
}

public interface ITeacher
{
   int WorkedHours {get; set;}
   decimal PayPerHour {get; private set;}
}

public class BiologicalStudent: IUniversityMember, IStudent
{
    public int CreditsToPast {get; private set;}

    public BiologicalStudent ()
    {
        CreditsToPast  = 5;
    }
    //stuff
    public int GetGPA()
    {
        return 3;
    }
}

public class MathStudent: IUniversityMember, IStudent
{
    public int CreditsToPast {get; private set;}

    public BiologicalStudent ()
    {
        CreditsToPast  = 9;
    }

    public int GetGPA()
    {
        return 2;
    }
}

public class BiologicalTeacher: IUniversityMember, ITeacher
{
     public int WorkedHours { get; set;}
     public decimal PayPerHour {get; private set;}

     public MathTeacher()
     {
         PayPerHour = 8;

     }
}

public class MathTeacher: IUniversityMember, ITeacher
{
     public int WorkedHours { get; set;}
     public decimal PayPerHour {get; private set;}

     public MathTeacher()
     {
         PayPerHour = 10;

     }
}
//Now if you have a university class

public class OxfordUniversity:IUniversity //can inherit interface too
{
     public int MinGAPForSchollarship {get; private set;}

     public OxfordUniversity()
     {
         MinGAPForSchollarship = 3;
     }

     public decimal PaySallary(ITeacher teacher)
     {
          return teacher.WorkedHours*teacher.PayPerHour;
     }

     public bool CheckForSchollarship(IStudent student)
     {
         int gpa = student.GetGPA();
         //do some checks

         if(gpa >= MinGAPForSchollarship)
            return true;

         return false;
     }
}

答案 3 :(得分:0)

看看.NET是如何解决这个问题的,你可以看到一些歧义。

例如,对于每个对象都有一个函数,你可以在其中请求对象的字符串表示:ToString(),即使字符串表示对于很多类来说可能不是一个有意义的事情

另一方面,尽管每个对象都可以自我克隆,但它们决定不让每个类都实现ICloneable。

对于您的应用程序(几乎每个)对象是否明智是一个共同的接口取决于您将使用此接口做什么以及实现此类接口的所有对象的优势与负责实施此接口的负担接口

例如,如果您正在谈论的实体是数据库记录,那么每个类很可能都有某种ID。您可以考虑为每个类提供一个带有一个get属性的接口,该属性返回记录ID的值。

public interface IID
{
    long ID {get;}
}

优点是多方面的:

  • 您鼓励数据库类的每个设计者实现相同类型的主键(在本例中为long),并且具有相同的属性名称
  • 优势:更容易发现记录的ID
  • 优点:更改ID的类型更容易
  • 优点:你知道你是否有数据库记录,你知道记录必须具备的一些功能,而不知道记录的类型。
  • 即使设计师需要不同的类型或不同的名称,他仍然可以创建一个特殊的功能来实现界面:

    公共类人员:IID {     public int ID {get;设置;}

    IID:ID {get {return this.ID;} }
    

    }

但是,我建议不要强制接口到对象是不自然的。这样做的好处是,您不能将这些奇怪的函数用于对它们没有实际用途的对象。

例如,代表某些有序数值的大多数类都有一些加法概念。不仅对于整数和实数,而且对于代表时间跨度的类:4天23小时+ 1天和7个我们= 6天6小时。因此,对于时间跨度,添加是一个有用的界面

但是,对于约会,添加没有意义:7月4日+ 14 juillet =?

所以:是的,为他们自然的项目实现接口。它们强制使用通用命名并启用重用。不,不要为那些对函数没有自然意义的项目实现它们。