依赖注入和项目参考[重复]

2024-04-25

我正在尝试了解 DI,以便更好地了解 IoC 以及其他好处。

在 DI 之前,我有一个项目,其中包含一个 UI 项目 (MVC)、一个 BusinessLogic 项目和一个 DataAccess 项目。我还有一个 SharedLib 项目。所有项目都引用 SharedLib。 UI 引用了 BusinessLogic,而 BusinessLogic 引用了 DataAccess。

我现在想添加接口。因此,我转到数据访问,为每个类添加一个接口,并用它们的方法填充它们。我对业务逻辑层也做了同样的事情。

但是为了注入我在 UI 项目的 BusinessLogic 类中实例化的 DataAccess 类,我需要对我的 Data 项目的引用,因为 UI 项目(我认为正确)不知道“IDataAccess”接口是什么。我能看到的唯一修复是将 UI 中的项目引用添加到我的 DA 项目 - 这似乎是错误的。

如果我尝试添加 Unity 作为我的容器(将来的某一天,一旦我弄清楚这一切是如何工作的),并且想要在 UI 项目中初始化我的接口/类关系 - 同样的问题。

也许接口必须放在某个共享项目中?或者一个项目?这应该如何处理?


如果您不想要项目之间的引用,您可以查看工厂/抽象工厂。

您的 UI 了解您的业务层,因此您希望在业务层中定义一个工厂,它知道如何使用数据层。然后,您可以在合成根(本示例中的 UI 项目)中处理所有 DI。

下面是一个使用控制台应用程序作为 UI 的简单示例,坚持您在问题中所述的参考文献

数据层

public interface IDataAccess
{
    string GetData();
}

public class XmlDataAccess : IDataAccess
{
    public string GetData()
    {
        return "some data";
    }
}

业务层

public interface IDataAccessFactory
{
    IDataAccess GetDataAccess();
}

public class XmlDataAccessFactory : IDataAccessFactory
{
    public IDataAccess GetDataAccess()
    {
        return new XmlDataAccess();
    }
}

public class BusinessLogic
{
    IDataAccessFactory dataAccessFactory;

    public BusinessLogic(IDataAccessFactory dataAccessFactory)
    {
        this.dataAccessFactory = dataAccessFactory;
    }

    public void DoSomethingWithData()
    {
        IDataAccess dataAccess = dataAccessFactory.GetDataAccess();
        Console.WriteLine(dataAccess.GetData());
    }

    public string GetSomeData()
    {
        IDataAccess dataAccess = dataAccessFactory.GetDataAccess();
        return dataAccess.GetData();
    }
}

UI

static void Main(string[] args)
{
    IUnityContainer container = new UnityContainer();
    container.RegisterType<IDataAccessFactory, XmlDataAccessFactory>();

    var logic = container.Resolve<BusinessLogic>();
    logic.DoSomethingWithData();

    string useDataInUI = logic.GetSomeData();
    Console.WriteLine("UI " + useDataInUI);

    Console.ReadKey();
}

这是一个人为的例子,所以看起来像是毫无意义的抽象,但如果有一个现实世界的例子,它会更有意义。

例如您的数据层数据库、xml 文件等中可能有一堆不同的数据访问类,因此您可以为业务层中的每个类定义一个工厂。


使用抽象工厂

工厂可以包含更多有关数据层实质的逻辑,或者作为抽象工厂向业务逻辑层提供一组单独的工厂。

业务层

相反,您可能在业务层中有一个抽象工厂,例如

public interface IPlatformFactory
{
    IDataAccessFactory GetDataAccessFactory();
    IPricingFactory GetPricingFactory(); // might be in the business project, or another project referenced by it
}

有一个混凝土工厂

public class WebPlatformFactory : IPlatformFactory
{
    IDataAccessFactory GetDataAccessFactory()
    {
        return new XmlDataAccessFactory();
    }

    IPricingFactory GetPricingFactory()
    {
        return new WebPricingFactory(); // not shown in the example
    }
}

(您可能还有其他具体工厂,例如RetailPlatformFactory, etc.)

Your BusinessLogic类现在看起来像

public class BusinessLogic
{
    IPlatformFactory platformFactory;

    public BusinessLogic(IPlatformFactory platformFactory)
    {
        this.platformFactory = platformFactory;
    }

    public void DoSomethingWithData()
    {
        IDataAccessFactory dataAccessFactory = platformFactory.GetDataAccessFactory();
        IDataAccess dataAccess = dataAccessFactory.GetDataAccess();
        Console.WriteLine(dataAccess.GetData());
    }

    public string GetSomeData()
    {
        IDataAccessFactory dataAccessFactory = platformFactory.GetDataAccessFactory();
        IDataAccess dataAccess = dataAccessFactory.GetDataAccess();
        return dataAccess.GetData();
    }
}

数据层

您的业​​务层不再需要提供IDataAccessFactory到您的 UI,以便您可以将其移动到本示例中的数据层中。所以数据层类是

public interface IDataAccess
{
    string GetData();
}

public class XmlDataAccess : IDataAccess
{
    public string GetData()
    {
        return "some data";
    }
}

public interface IDataAccessFactory
{
    IDataAccess GetDataAccess();
}

public class XmlDataAccessFactory : IDataAccessFactory
{
    public IDataAccess GetDataAccess()
    {
        return new XmlDataAccess();
    }
}

UI

现在,您可以在 UI 中配置容器并执行类似的操作:

static void Main(string[] args)
{
    IUnityContainer container = new UnityContainer();
    container.RegisterType<IPlatformFactory, WebPlatformFactory>();

    var logic = container.Resolve<BusinessLogic>();
    logic.DoSomethingWithData();

    string useDataInUI = logic.GetSomeData();
    Console.WriteLine("UI " + useDataInUI);

    Console.ReadKey();
}

然后,UI 对数据层/访问一无所知,它只是将工厂创建移交给业务层,该业务层保存数据(和定价)引用。

一些推荐阅读:

成分根 http://blog.ploeh.dk/2011/07/28/CompositionRoot/

实现抽象工厂 http://blog.ploeh.dk/2012/03/15/ImplementinganAbstractFactory/

自信地构建对象图 http://blog.ploeh.dk/2011/03/04/Composeobjectgraphswithconfidence/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

依赖注入和项目参考[重复] 的相关文章

  • 在 VS2017 下使用 Conan 和 CMake 项目进行依赖管理

    我正在尝试使用 CMake 与 VS2017 集成为 C 设置一个开发环境 以便在 Linux x64 下进行编译 为了更好地管理依赖关系 我选择使用 Conan 但我对这个软件还很陌生 我想知道让 VS2017 识别项目依赖关系的最佳方法
  • 内联函数/方法

    声明 内联函数必须在调用之前定义 这个说法正确吗 EDIT 该问题最初是德语 内联功能穆森 弗 伊赫雷姆 奥夫鲁夫定义 sein 也许它对任何人都有帮助 是的 它是正确的 但只是部分正确 它可能正确地重新构建如下 内联函数必须在每个翻译单位
  • Subversion 和 Visual Studio 项目的最佳实践

    我最近开始在 Visual Studio 中处理各种 C 项目 作为大型系统计划的一部分 该系统将用于替换我们当前的系统 该系统是由用 C 和 Perl 编写的各种程序和脚本拼凑而成的 我现在正在进行的项目已经达到了颠覆的临界点 我想知道什
  • 在 C# 中生成 HMAC-SHA1

    我正在尝试使用 C 来使用 REST API API 创建者提供了以下用于 hmac 创建的伪代码 var key1 sha1 body var key2 key1 SECRET KEY var key3 sha1 key2 var sig
  • 劫持系统调用

    我正在编写一个内核模块 我需要劫持 包装一些系统调用 我正在暴力破解 sys call table 地址 并使用 cr0 来禁用 启用页面保护 到目前为止一切顺利 一旦完成 我将公开整个代码 因此如果有人愿意 我可以更新这个问题 无论如何
  • 对 boost 库的依赖项没有完整路径

    我已经成功构建了动态库 依赖于使用自定义前缀构建和安装的 boost 库 b2 install prefix PREFIX 然而 当我跑步时otool L在我的库中 我得到如下输出 libboost regex dylib compatib
  • 从 Code::Blocks 运行程序时出现空白控制台窗口 [重复]

    这个问题在这里已经有答案了 当我尝试在 Code Blocks 中构建并运行新程序时 控制台窗口弹出空白 我必须单击退出按钮才能停止它 它对我尝试过的任何新项目 包括 Hello world 都执行此操作 奇怪的是 它对于我拥有的任何旧项目
  • 预处理后解析 C++ 源文件

    我正在尝试分析c 使用我定制的解析器的文件 写在c 在开始解析之前 我想摆脱所有 define 我希望源文件在预处理后可以编译 所以最好的方法是运行C Preprocessor在文件上 cpp myfile cpp temp cpp or
  • 为什么具有相同名称但不同签名的多个继承函数不会被视为重载函数?

    以下代码片段在编译期间产生 对 foo 的调用不明确 错误 我想知道是否有任何方法可以解决此问题而不完全限定对 foo 的调用 include
  • 默认析构函数做了多少事情

    C 类中的默认析构函数是否会自动删除代码中未显式分配的成员 例如 class C public C int arr 100 int main void C myC new C delete myC return 0 删除 myC 会自动释放
  • 分配器感知容器和propagate_on_container_swap

    The std allocator traits模板定义了一些常量 例如propagate on container copy move assign让其他容器知道它们是否应该在复制或移动操作期间复制第二个容器的分配器 我们还有propag
  • .NET 客户端中 Google 表格中的条件格式请求

    我知道如何在 Google Sheets API 中对值和其他格式进行批量电子表格更新请求 但条件格式似乎有所不同 我已正确设置请求 AddConditionalFormatRuleRequest formatRequest new Add
  • 为什么要在 C++ 中使用 typedef?

    可以说我有 set
  • DataTable:通过 LINQ 或 LAMBDA 进行动态 Group By 表达式

    我有一个数据表 我想在其中对未指定数量的字段进行分组 发生这种情况的原因是用户可以选择他想要分组的字段 所以 实际上 我将选择推入列表中 在这个选择上 我必须对我的数据表进行分组 想象一下这段代码 VB 或 C 都一样 public voi
  • 初始化 LPCTSTR /LPCWSTR [重复]

    这个问题在这里已经有答案了 我很难理解并使其正常工作 基本上归结为我无法成功初始化这种类型的变量 它需要有说的内容7 2E25DC9D 0 USB003 有人可以解释 展示这种类型的正确初始化和类似的值吗 我已查看此站点上的所有帮助 将项目
  • 使用 HTMLAgilityPack 从节点的子节点中选择所有

    我有以下代码用于获取 html 页面 将网址设置为绝对 然后将链接设置为 rel nofollow 并在新窗口 选项卡中打开 我的问题是关于将属性添加到 a s string url http www mysite com string s
  • Visual Studio 2017 完全支持 C99 吗?

    Visual Studio 的最新版本改进了对 C99 的支持 最新版本VS2017现在支持所有C99吗 如果没有 C99 还缺少哪些功能 No https learn microsoft com en us cpp visual cpp
  • 为什么 Linux 对目录使用 getdents() 而不是 read()?

    我浏览 K R C 时注意到 为了读取目录中的条目 他们使用了 while read dp gt fd char dirbuf sizeof dirbuf sizeof dirbuf code Where dirbuf是系统特定的目录结构
  • C++、三元运算符、std::cout

    如何使用 C 用三元运算符编写以下条件 int condition1 condition2 condition3 int double result int or double std cout lt lt condition1 resul
  • 如何使用 C# 以低分辨率形式提供高分辨率图像

    尝试使用 300dpi tif 图像在网络上显示 目前 当用户上传图像时 我正在动态创建缩略图 如果创建的页面引用宽度为 500x500px 的高分辨率图像 我可以使用相同的功能即时转换为 gif jpg 吗 将创建的 jpg 的即将分辨率

随机推荐

  • Python - PIP 安装故障排除 - PermissionError: [WinError 5] 访问被拒绝

    使用 PIP 安装新软件包甚至将 pip 本身升级到最新版本时出现以下错误 我正在 Windows 8 1 机器上使用 Python 3 4 运行 pip 该消息告诉我我没有文件的管理权限 我的帐户是管理员帐户 我很感激任何关于如何解决这个
  • createElement() 与innerHTML 何时使用?

    我在sql表中有一些数据 我通过 JSON 将其发送到我的 JavaScript 从那里我需要将其组成 HTML 以便通过两种方式之一向用户显示 通过编写 html 字符串并插入到持有元素的 innerHTML 属性中 通过对我需要的每个元
  • 使用 PHP GD 将文本置于图像中心

    所以我正在创建一个横幅生成器 我将在中间添加文本 但希望它正好位于中心 我知道imagettftext可以用来在横幅上书写 但这不会使其居中 一个可能的解决方案可能是找到文本的宽度 然后使用从横幅宽度的一半中取出的一半 但我不知道如何做到这
  • 如何限制登录尝试 - PHP & MySQL & CodeIgniter

    我希望能够根据失败的尝试来限制登录尝试 但我有一些问题 我应该使用 MySQL 吗 读到它可能会给数据库带来压力 我应该在每个用户和系统范围内进行限制还是仅在系统范围内进行限制 这样可以防止普通人猜测密码 我应该如何计算我的阈值 因此它会自
  • Django Rest Auth 自定义密码重置链接

    我已经尝试过针对类似问题找到的解决方案 但没有一个对我有用 我使用的是 Angular 前端 DRF Django Rest Auth 对于确认 url 我能够通过添加看起来像这样的自定义适配器来覆盖它以指向我的前端 class Accou
  • 防止同一用户在桌面应用程序上登录

    我正在开发一个多用户桌面应用程序 我需要找到一种方法 让每个用户名一次只允许一个用户登录 基本上 John 无法从 PC A 登录应用程序 然后再运行到 PC B 并登录 我的想法是设置一个位标志来指示用户已登录 并且当从另一个位置进行尝试
  • 为什么Python中set的大小可以比dict大?

    为什么a的大小是set比一个大dict s set d for i in range 20 s add i d i 1 print f i 1 s sizeof d sizeof Output 17 712 624 18 712 624 1
  • 如何在 Google Dataproc 集群中安装 python 包

    创建并运行集群后 是否可以在 Google Dataproc 集群中安装 python 包 我尝试使用 pip install xxxxxxx 在主命令行中 但它似乎不起作用 Google的Dataproc文档没有提及这种情况 创建集群后
  • 按组添加ID列[重复]

    这个问题在这里已经有答案了 我想根据两列纬度和经度在 R 中创建一个唯一 ID 以便重复的位置具有相同的集群 ID 例如 LAT LONG Cluster ID 13 5330 15 4180 1 13 5330 15 4180 1 13
  • MemoryCache 的大小设置意味着什么?

    在控制器类中 我有 using Microsoft Extensions Caching Memory private IMemoryCache cache private readonly MemoryCacheEntryOptions
  • PHP 创建日期范围

    以这种格式的日期开始 2011 05 01 09 00 00 如何创建一个包含一年中所有工作日 因此排除所有周六和周日 的所有办公时间 09 00 到 17 00 的数组 我想要达到的是这样的 2011 05 01 09 00 00 201
  • 重置远程跟踪分支

    如何将远程跟踪分支的分支指针重置为其之前的提交之一 这样看起来我没有拉动 类似于本地分支的硬重置 您可以使用以下命令设置对任何其他提交的引用 git update ref refs remotes origin master
  • 如何从 VB-6 旧应用程序中启动屏幕键盘程序

    我正在尝试从 Windows 10 32 或 Windows 10 64 位计算机上的 VB 6 应用程序中 shell osk exe 过去我们只是简单地使用 Private Sub Command1 Click Dim strTemp
  • 您能否将 TeamCity“工件”配置为重新检入源代码管理?

    我希望将 TeamCity Artifacts 重新签入源代码管理 我以前使用过 TFS Integrator 所以我习惯了它的方法 通过配置 它可以将输出构建签入源代码管理 然后 当人们进行 get 操作时 他们将收到这些文物 或者是否有
  • 指定共享对象(共享库)的名称

    Go 编译器为共享对象生成的名称是错误的 例子 go install buildmode shared linkshared github com apache thrift lib go thrift code google com p
  • Windows 安装程序和安装应用程序合并到一个文件中?

    我使用 Visual Studio 在 C 中编写了一个应用程序 我创建了一个项目设置文件 该文件在我的调试中为我创建了文件 Windows Installer 和安装应用程序都是必需的 但我想将它们合并为一个 就像当您下载应用程序时 安装
  • java中删除文件中的一行

    好的 所以我尝试使用 java lang String 从文本文件中删除行 目前我这样做的方式是跟踪行号并输入索引 索引是我要删除的行 因此 每次读取新的数据行时 我都会增加行数 现在 当我达到相同索引的行数时 我不会将数据写入临时文件 现
  • asp.net mvc相当于rails回调before_save

    您好 我正在寻找一个 ASP NET MVC 回调 以便在保存模型之前获取详细数据 Rails 中有 before save Thanks 如果您正在使用实体框架 您的标签表明 那么这个 StackOverflow 帖子 https sta
  • Async CTP 可以与可移植库一起使用吗

    我想看看异步 CTP 是否带有可移植类库 不可以 异步 CTP 对于桌面 电话 Silverlight 4 和 Silverlight 5 有不同的 dll 希望在不久的将来 所有这些平台都将原生支持任务 和异步 然后可移植类库将能够使用异
  • 依赖注入和项目参考[重复]

    这个问题在这里已经有答案了 我正在尝试了解 DI 以便更好地了解 IoC 以及其他好处 在 DI 之前 我有一个项目 其中包含一个 UI 项目 MVC 一个 BusinessLogic 项目和一个 DataAccess 项目 我还有一个 S