首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >界面粒度

界面粒度
EN

Stack Overflow用户
提问于 2019-06-07 04:05:04
回答 1查看 40关注 0票数 0

在我今天的工作中,我开始与我的Interfaces的切片斗争。

为了在我的应用程序中维护一些主数据,我构建了一个上下文。此上下文需要数据提供者获取其所需的信息,并将其带入持久保存的策略。

在第一次尝试中,我在我的上下文中构建了一个方法来设置Dataprovider。例如,一个基于文件,一个来自数据库。

代码语言:javascript
复制
Context->setData(MyProvider->getData() ) ;

数据提供程序需要一些不同的设置来完成这项工作。基于文件的需要Filepath,而数据库提供了一个Modelobject。

现在我不确定,定义接口的最佳方式是什么。创建一个通用接口"Provider“,并关注getData方法的返回类型。或者继承,为Fileprovider构建一个特殊的接口,然后为Database创建一个特殊的接口。

代码语言:javascript
复制
Interface Fileprovider extends IProvider { void setPath(String Path) ;} 

第三种可能就是为每个提供者创建一个独立的接口。

感谢你们的支持

EN

回答 1

Stack Overflow用户

发布于 2019-06-07 08:12:45

我建议使用组合和基础IProvider接口(您的第二种方法)。每个提供者可能会有一些独立的特殊功能,因此应该封装(接口隔离原则):

代码语言:javascript
复制
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”)推荐了一些很好的理由来避免这种设计。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56484399

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档