每个实体实现接口

本文关键字:接口 实现 实体 | 更新日期: 2023-09-27 18:16:01

目前,我正在研究应用程序的体系结构,我的项目中有许多实体,即学生教师大学,我想知道所有实体必须实现接口是否是一个好的做法。这将帮助我在依赖注入?从架构的角度来看,什么是最佳实践。

 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接口是空的。

每个实体实现接口

不一定。如果在这种情况下,Student和Teacher有一些共同的功能,那么一个共享的接口将是一种方法。

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:实现跨多个类的接口,如果这些类实现相关的方法和函数是有意义的,而不是仅仅作为一个笼统的规则。

我认为解耦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中我们仍然有一个耦合问题,所以在这一点上,我们将不得不实现一个依赖注入,像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
  }
}

是的,看起来不错。我们已经完全消除了耦合

问题,如果将来我们只需要取A,删除它并替换为新的更酷的东西,这将非常容易。

显然,过度使用它是一个不好的实践,我相信只有在仔细规划以避免无用的实现之后才能使用DI。

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

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

我不认为你项目中的每个模型都需要实现一个接口或DI,只要考虑一下,看看哪里有用,哪里有点小题大做

看看。net是如何解决这个问题的,你会发现一些模棱两可。

例如,对于每个对象都有一个函数,您可以请求对象的字符串表示:ToString(),尽管对于字符串表示可能对许多类来说没有意义

另一方面,尽管对于每个对象来说克隆自己是一个有用的函数,但他们决定不让每个类都实现iclonable。

让应用程序的(几乎所有)对象都有一个公共接口是否明智,取决于你将如何处理这个接口,以及所有对象实现这样一个接口的优势与被迫实现这个接口的负担。

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

public interface IID
{
    long ID {get;}
}

优点是多方面的:

  • 您鼓励每个数据库类的设计者实现相同类型的主键(在本例中是长键)和相同的属性名
  • 优点:更容易发现记录的ID
  • 优点:更容易更改ID类型
  • 优点:你知道如果你有一个数据库记录,你知道记录必须具有的一些功能,而不需要真正知道记录的类型。
  • 即使设计者需要一个不同的类型,或者不同的名字,他仍然可以创建一个特殊的函数来实现接口:

    公共类Person: IID{公共int ID{获取;设置;}

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

    }

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

例如,大多数表示有序数值的类都有加法的概念。不仅适用于整数和实数,还适用于表示时间跨度的类:4天23小时+ 1天7小时= 6天6小时。所以对于时间跨度来说加法是一个很有用的接口

然而,对于日期,加法没有意义:7月4日+ 14朱丽叶= ?

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

是的,这样做,这是最好的做法。这为您提供了多态性的优势。你应该用更好的方法在当前的情况下是不好的,因为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;
     }
}