构造函数注入以及何时使用服务定位器

发布于 2024-10-09 16:49:07 字数 2758 浏览 0 评论 0原文

我正在努力理解 StructureMap 的部分用法。 特别是,在文档中声明了一种常见的反模式,即仅使用 StructureMap 作为服务定位器而不是构造函数注入(直接来自 Structuremap 文档的代码示例):

 public ShippingScreenPresenter()
    {
        _service = ObjectFactory.GetInstance<IShippingService>();
        _repository = ObjectFactory.GetInstance<IRepository>();
    }

而不是:

public ShippingScreenPresenter(IShippingService service, IRepository repository)
    {
        _service = service;
        _repository = repository;
    }

这对于非常短的对象来说很好图形,但是当处理多层对象时,这是否意味着您应该从顶部传递更深层次对象所需的所有依赖项?当然,这破坏了封装并暴露了太多有关更深层次对象的实现的信息。

假设我正在使用活动记录模式,因此我的记录需要访问数据存储库才能保存和加载自身。如果此记录加载到对象内,该对象是否会调用 ObjectFactory.CreateInstance() 并将其传递到活动记录的构造函数中?如果该对象位于另一个对象内部怎么办?它是否将 IRepository 作为自己的参数?这将向父对象公开我们此时正在访问数据存储库的事实,而外部对象可能不应该知道这一点。

public class OuterClass
{
    public OuterClass(IRepository repository)
    {
        // Why should I know that ThingThatNeedsRecord needs a repository?
        // that smells like exposed implementation to me, especially since
        // ThingThatNeedsRecord doesn't use the repo itself, but passes it 
        // to the record.
        // Also where do I create repository? Have to instantiate it somewhere
        // up the chain of objects
        ThingThatNeedsRecord thing = new ThingThatNeedsRecord(repository);
        thing.GetAnswer("question");
    }
}

public class ThingThatNeedsRecord
{
    public ThingThatNeedsRecord(IRepository repository)
    {
        this.repository = repository;
    }

    public string GetAnswer(string someParam)
    {
        // create activeRecord(s) and process, returning some result
        // part of which contains:
        ActiveRecord record = new ActiveRecord(repository, key);
    }

    private IRepository repository;
}

public class ActiveRecord
{
    public ActiveRecord(IRepository repository)
    {
        this.repository = repository;
    }

    public ActiveRecord(IRepository repository, int primaryKey);
    {
        this.repositry = repository;
        Load(primaryKey);
    }

    public void Save();

    private void Load(int primaryKey)
    {
        this.primaryKey = primaryKey;
        // access the database via the repository and set someData
    }

    private IRepository repository;
    private int primaryKey;
    private string someData;
}

任何想法将不胜感激。

西蒙

编辑: 意见似乎是注入应该从顶层开始。 ActiveRecord 将被注入到 ThingThatNeedsRecord 中,而 ThingThatNeedsRecord 又被注入到 OuterClass 中。 这样做的问题是,如果 ActiveRecord 需要使用运行时参数(例如要检索的记录的 id)进行实例化。如果我将 ActiveRecord 注入到 ThingThatNeedsRecord 的顶部,我必须以某种方式弄清楚此时需要什么 id (这会将顶层暴露给不应该实现的实现),或者我必须有一个部分构造的 ActiveRecord并稍后设置 Id。如果我需要 N 条记录并且直到执行 ThingThatNeedsRecord 内的逻辑才知道,这会变得更加复杂。

I'm struggling to understand parts of StructureMap's usage.
In particular, in the documentation a statement is made regarding a common anti-pattern, the use of StructureMap as a Service Locator only instead of constructor injection (code samples straight from Structuremap documentation):

 public ShippingScreenPresenter()
    {
        _service = ObjectFactory.GetInstance<IShippingService>();
        _repository = ObjectFactory.GetInstance<IRepository>();
    }

instead of:

public ShippingScreenPresenter(IShippingService service, IRepository repository)
    {
        _service = service;
        _repository = repository;
    }

This is fine for a very short object graph, but when dealing with objects many levels deep, does this imply that you should pass down all the dependencies required by the deeper objects right from the top? Surely this breaks encapsulation and exposes too much information about the implementation of deeper objects.

Let's say I'm using the Active Record pattern, so my record needs access to a data repository to be able to save and load itself. If this record is loaded inside an object, does that object call ObjectFactory.CreateInstance() and pass it into the active record's constructor? What if that object is inside another object. Does it take the IRepository in as its own parameter from further up? That would expose to the parent object the fact that we're access the data repository at this point, something the outer object probably shouldn't know.

public class OuterClass
{
    public OuterClass(IRepository repository)
    {
        // Why should I know that ThingThatNeedsRecord needs a repository?
        // that smells like exposed implementation to me, especially since
        // ThingThatNeedsRecord doesn't use the repo itself, but passes it 
        // to the record.
        // Also where do I create repository? Have to instantiate it somewhere
        // up the chain of objects
        ThingThatNeedsRecord thing = new ThingThatNeedsRecord(repository);
        thing.GetAnswer("question");
    }
}

public class ThingThatNeedsRecord
{
    public ThingThatNeedsRecord(IRepository repository)
    {
        this.repository = repository;
    }

    public string GetAnswer(string someParam)
    {
        // create activeRecord(s) and process, returning some result
        // part of which contains:
        ActiveRecord record = new ActiveRecord(repository, key);
    }

    private IRepository repository;
}

public class ActiveRecord
{
    public ActiveRecord(IRepository repository)
    {
        this.repository = repository;
    }

    public ActiveRecord(IRepository repository, int primaryKey);
    {
        this.repositry = repository;
        Load(primaryKey);
    }

    public void Save();

    private void Load(int primaryKey)
    {
        this.primaryKey = primaryKey;
        // access the database via the repository and set someData
    }

    private IRepository repository;
    private int primaryKey;
    private string someData;
}

Any thoughts would be appreciated.

Simon

EDIT:
Opinion seems to be that the injection should start at the top layer. ActiveRecord would be injected into ThingThatNeedsRecord which is injected into OuterClass.
The problem with this would be that if ActiveRecord needs to be instantiated with a run-time parameter (the id of the record to retrieve for example). If I'm injecting ActiveRecord into ThingThatNeedsRecord right at the top, I somehow have to figure out what id needs to be at that point (which exposes the top layer to implementation which it shouldn't) or I have to have a partially constructed ActiveRecord and set the Id later on. This becomes more complicated if I need N records and won't know until execution of logic inside ThingThatNeedsRecord.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

无法回应 2024-10-16 16:49:08

控制反转就像暴力。如果它不能解决您的问题,则说明您使用的还不够。或者类似的东西

更重要的是,我认为您的 OuterClass 应该通过构造函数注入将 ThingThatNeedsRecord 注入其中。同样,ThingThatNeedsRecord 应该将 ActiveRecord 注入其中。这不仅可以解决您眼前的问题,还可以使您的代码更加模块化和可测试。

Inversion of Control is like violence. If it doesn't solve your problem, you're not using enough of it. Or something like that.

More to the point, I think your OuterClass should have ThingThatNeedsRecord injected into it via constructor injection. Likewise ThingThatNeedsRecord should have ActiveRecord injected into it. Not only will this solve your immediate problem, but it will make your code more modular and testable as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文