在我今天的工作中,我开始与我的Interfaces的切片斗争。
为了在我的应用程序中维护一些主数据,我构建了一个上下文。此上下文需要数据提供者获取其所需的信息,并将其带入持久保存的策略。
在第一次尝试中,我在我的上下文中构建了一个方法来设置Dataprovider。例如,一个基于文件,一个来自数据库。
Context->setData(MyProvider->getData() ) ;数据提供程序需要一些不同的设置来完成这项工作。基于文件的需要Filepath,而数据库提供了一个Modelobject。
现在我不确定,定义接口的最佳方式是什么。创建一个通用接口"Provider“,并关注getData方法的返回类型。或者继承,为Fileprovider构建一个特殊的接口,然后为Database创建一个特殊的接口。
Interface Fileprovider extends IProvider { void setPath(String Path) ;} 第三种可能就是为每个提供者创建一个独立的接口。
感谢你们的支持
发布于 2019-06-07 08:12:45
我建议使用组合和基础IProvider接口(您的第二种方法)。每个提供者可能会有一些独立的特殊功能,因此应该封装(接口隔离原则):
Main()
{
Context context = new Context();
IFileDataProvider fileDataProvider = new FileDataProvider();
// Configure the provider
fileDataProvider->setPath("c:\data");
context->setProvider(fileDataProvider);
// Get data. Internally this data is read from the local filesystem
DataResultObject data = context->getData();
IDatabaseProvider databaseProvider = new DatabaseProvider();
// Configure the provider
databaseProvider->login();
context->setProvider(databaseProvider);
// Get data. Internally this data is now read from the database
DataResultObject data = context->getData();
// A test case would fake the data provider to reduce complexity and improve performance.
// To achieve this a third implementation (a dummy) would be required.
IProvider fakeDataProvider = new MockDataProvider();
context->setProvider(fakeDataProvider);
// Get test data. Internally this data is created by the fake data provider
DataResultObject data = context->getData();
}
interface IProvider
{
DataResultObject getData();
}
interface IFileDataProvider extends IProvider
{
void setPath(String path);
}
class FileDataProvider implements IFileDataProvider
{
void setPath(String path)
{
this->path = path;
}
DataResultObject getData()
{
return readFromFilesystem();
}
}
interface IDatabaseProvider extends IProvider
{
void login();
}
class DatabaseProvider implements IDatabaseProvider
{
private String credentials = "login credentials";
void login()
{
login(this->credentials);
}
DataResultObject getData()
{
return readFromDatabase();
}
}
class MockDataProvider implements IProvider
{
DataResultObject getData()
{
// return empty or dummy data
return new DataResultObject();
}
}
class Context
{
IProvider provider;
public Context(IProvider provider)
{
this.provider = provider;
}
public DataResultObject getData()
{
return this.provider->getData();
}
public void setContext(IProvider provider)
{
this.provider = provider;
}
}如果在同一个Context对象上更改IProvider实例,那么我会添加一个setter来切换实例。否则,构造函数是更好的选择。
为每种提供程序类型使用专用接口将消除在提供程序之间切换的选项,因为这将消除多态性。在编写单元测试时,这种切换可能会很有用。然后,您可以轻松地模拟数据库或文件系统。
并且使用单个共享接口将迫使例如DatabaseProvider实现冗余的FileDataProvider特定方法。当类包含虚拟实现时,这可能会非常恼人和混乱。接口分离原则(SOLID中的“i”)推荐了一些很好的理由来避免这种设计。
https://stackoverflow.com/questions/56484399
复制相似问题