【发布时间】:2025-12-06 03:05:02
【问题描述】:
我的灵感来自于接口实现的封装。当对象共享公共属性和方法时,接口是一个强大的工具。面向接口的设计是将实体和管理它们的管理器分离的设计。他们不需要知道任何实现细节和确切的类型,典型的良好接口设计是通过方法调用的对象可以在运行时热插拔。
所以我设法将我的对象通过接口公开。
假设我有一个LoginModule,其中包含处理Client 提交的Form 的业务逻辑。例如,客户端可以通过输入Username 和Password 或使用他们的MobileNo 登录
public class UserLoginForm
{
public string Username { get; set; }
public string Password { get; set; }
}
public class MobileLoginForm
{
public string MobileNo { get; set; }
public string Password { get; set; }
}
然后业务逻辑层去看看请求。
public class LoginModule
{
public int LoginByUsername(UserLoginForm form)
{
// DoSomething, such as CheckDbIfExist(form.Username);
// return the result, e.g. -1 stand for wrong password
}
public int LoginByMobileNo(MobileLoginForm form)
{
// DoSomething, such as CheckDbIfExist(form.Username);
// return the result, e.g. -1 stand for wrong password
}
}
在这个例子中,两个逻辑非常相似,以至于LoginByMobileNo最终可以通过在数据库中查找MobileNo得到Username后直接调用LoginByUserName。
但你知道,它不能,因为我们需要一个UserLoginForm 来调用它,或者我们只是创建一个单独的方法Login(string username, string password) 让两个登录方法都调用它。
实际考虑的不是如何重构这两种方法,因为还有许多其他类型的请求,例如CokeRequest 请求将可乐运送到int RoomNo 和int Count... ...
public interface ILoginModule
{
void LoginByUsername(XXX xxx);
}
第一个问题:XXX 是什么?
这个接口无权访问UserLoginForm,反正他也不知道那个表单的存在。如果我做的界面设计正确,XXX应该是一个他可以知道它存在的界面。
public interface ILoginModule
{
void LoginByUsername(IUserLogin login);
void LoginByMobile(IMobileLogin login);
}
// LoginModule now implement ILoginModule
public interface IUserLogin
{
string UserName { get; set; }
string Password { get; set; }
}
public interface IMobileLogin
{
string MobileNo { get; set; }
string Password { get; set; }
}
// The the two Forms now implement the respective interface
到那时,噩梦开始了。我发现客户提出的每个请求都需要一个专用接口
一个有趣的观察:
服务接口是纯方法接口
请求接口是纯属性接口
我不认为这是处理接口的正确方法。
如果我们将接口碎片化,也不会。
public interface ILoginModule
{
void LoginByUsername(IUserLogin login);
void LoginByMobile(IMobileLogin login);
}
// LoginModule now implement ILoginModule
public interface IPassword
{
string Password { get; set; }
}
public interface IUserLogin : IPassword
{
string UserName { get; set; }
}
public interface IMobileLogin : IPassword
{
string MobileNo { get; set; }
}
// The the two Forms now implement the respective interface
因为我们仍然需要数百个接口(与请求的种类相同) 也没有
public interface ILoginModule
{
void LoginByUsername(IUser login1, IPassword login2);
void LoginByMobile(IMobile login, IPassword login2);
}
// LoginModule now implement ILoginModule
public interface IPassword
{
string Password { get; set; }
}
public interface IUser
{
string UserName { get; set; }
}
public interface IMobile
{
string MobileNo { get; set; }
}
// The the two Forms now implement the respective interface
它闻起来很糟糕,因为我们与一个一个传递字符串内容没有什么不同。如果请求包含8个参数,则方法变为DoWork(form,form,form,form,form,form,form,form)
我真的不明白为什么我会陷入这种讽刺。如果我有n种请求,把它们交给m个模块来处理是正常的,总共还是n个方法。如果我们使用接口,它会添加 n 个接口来表示 n 个请求,这对随时热插拔数据没有帮助,因为每个接口只有一个实现。
在这种情况下,LoginModule 甚至无法从中受益:在任何情况下,它都无法在找到对应于MobileNo 的Username 后调用LoginByUsername...
大多数接口教程都在使用 car 和 bus 和 racecar,其中 void StartEngine()...虽然很少用于架构或层之间的通信,例如 MVC 模型。
我并不是说接口不好,但我需要一种方法来正确实现它,或者我应该在这种情况下实现它。毫无疑问,任何滥用的模式都是反模式。 我希望听到任何声音。
【问题讨论】:
标签: c# design-patterns interface