每个实体实现接口
本文关键字:接口 实现 实体 | 更新日期: 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;
}
}