温莎 - 从容器拉临时对象容器、对象、温莎

2023-09-02 01:18:03 作者:踏云归

我如何从拉是一过性的容器中的对象?我一定要与容器注册这些注入的需要类的构造函数?一切都注入到构造手感并不好。也只有一类,我不希望创建一个 TypedFactory 和工厂注入到需要的类。

这是来找我的另一个想法是新起来的必要基础。但我也注入日志组件(通过属性)为我所有的类。所以,如果我新的他们,我将不得不手动实例日志在这些类中。我怎样才能继续使用该容器为我所有的班?

记录器注入:的我的大部分课程都在日志属性除非有继承链中,(在这种情况下,只有基类具有这种特性,并且所有的派生类使用)。当这些都通过温莎容器实例,他们会得到我的执行 ILogger 注射到他们。

  //安装QueueMonitor作为单身
Container.Register(Component.For&其中; QueueMonitor>()LifestyleSingleton());
//安装数据处理器为Trnsient
Container.Register(Component.For&其中;数据处理器>()LifestyleTransient());

Container.Register(Component.For<数据>()LifestyleScoped());

公共类QueueMonitor
{
    私人数据处理器;

    公共ILogger记录器{获得;组; }

    公共无效OnDataReceived(数据资料)
    {
        //从工厂拉数据处理器
        dataProcessor.ProcessData(数据);
    }
}

公共类数据处理器
{
    公共ILogger记录器{获得;组; }

    公共记录[]过程数据(数据资料)
    {
        //数据可以有多个记录
        //循环遍历数据,并创造新的记录集
        //这是为了创造新的纪录正确的方法是什么?
        //我如何使用的容器在这里和避免新
        录制录制=新记录(/ *使用数据* /);
        ...

        //返回记录列表
    }
}


公共类记录
{
    公共ILogger记录器{获得;组; }

    私人_recordNumber;
    私人_recordOwner;

    公共字符串GetDescription()
    {
        Logger.LogDebug(登录的东西);
        //返回定制描述
    }
}
 

问题:

如何创建新的记录对象,而不使用新?

QueueMonitor 辛格尔顿,而数据在作用域。我怎么可以注入数据 OnDataReceived()的方法?

解决方案

从样品,你给它很难做到非常具体,但在一般情况下,当你注入 ILogger 实例到大多数的服务,你应该问自己两件事情:

请登录我的太多了? 请我违反了SOLID原则?

1。难道我登录了太多

7 17 从秘境九寨到圣境甘南 黄龙 扎尕那 郞木寺 拉卜楞寺

正在记录太多,当你有很多code是这样的:

 尝试
{
   //此处一些操作。
}
赶上(例外前)
{
    this.logger.Log(前);
    扔;
}
 

写作code像这样来自丢失的错误信息的关注。然而,复制这些类型的try-catch块的所有的地方,并没有帮助。更糟糕的是,我经常看到开发者登录并继续(它们删除最后一个抛出语句)。这是非常糟糕的(闻起来像老VB 出错时继续下一步),因为在大多数情况下,你根本就没有足够的信息来确定它是否是安全的继续。经常有在导致操作失败的code的错误。继续意味着用户往往得到的想法,操作成功,而它也没有。问问你自己:更糟糕的是,显示用户的一般错误消息说,有什么出了错,或者静静地跳过错误,让用户觉得他的请求被成功处理?想想用户会感觉如何,如果他发现了两个星期后,他的命令是从来没有发货。你可能会失去一个客户。更糟的是,患者的 MRSA 注册默默的失败,从而导致不​​被护士被隔离,并导致污染病人其他患者,导致成本高或者甚至死亡。

大多数这类的try-catch-日志行应该被删除,您应该简单地让异常泡了调用堆栈。

如果你不记录?你绝对应该!但是,如果可以的话,定义一个try-catch块在应用程序的顶部。在ASP.NET,您可以实现的Application_Error 事件,注册 HTTP模块或定义自定义错误页,做的日志记录。与Win表单解决方案有所不同,但概念保持不变:定义一个单独的顶级最包罗万象

但是有时候,你仍然想捕捉和记录一个特定类型的异常。系统我在过去的工作,让我们的业务层抛出 ValidationException s,这将捕获的presentation层。这些例外包含验证信息以显示给用户。因为这些异常会被逮住,并在presentation层处理,他们也不会冒泡到应用程序的最上面的部分,并没有结束,在应用程序的包罗万象的code。不过我想记录这些信息,只需找出多久用户输入无效信息,并找出是否在那里引发了正当的理由的验证。所以这是没有错误记录;只是记录。我写了下面code要做到这一点:

 尝试
{
   //此处一些操作。
}
赶上(ValidationException前)
{
    this.logger.Log(前);
    扔;
}
 

看起来很熟悉?是的,看起来完全一样的previous code段,与我只抓到 ValidationException S中的差异。然而,还有一个区别,那不能只看该片段中可以看出。有中包含了code中的应用程序只有一个地方!这是一个装饰,这使我下一个问题你应该问自己:

2。我是否违反了SOLID原则?

之类的东西日志,审计和安全性,被称为横切关注(或问题)。它们被称为横切,因为它们可以跨越应用程序的多个层,并且必须经常被应用到许多类在系统中。但是,当你发现你写code供他们使用的许多类在系统中,你最有可能违反了SOLID原则。就拿下面的例子:

 公共无效MoveCustomer(INT客户ID,地址newAddress)
{
    VAR手表= Stopwatch.StartNew();

    //实际操作

    this.logger.Log(MoveCustomer在执行+
        watch.ElapsedMiliseconds +毫秒。);
}
 

下面我们测量才能执行 MoveCustomer 操作的时间,我们记录这些信息。这是非常可能的是系统中的其他操作都需要此相同的横切关注。你会开始增加code这样你的的ShipOrder CancelOrder CancelShipping 等方法,最终这导致了很多code复制,并最终维护的噩梦。

这里的问题是违反了 SOLID 的原则。 SOLID原则是一组面向对象的设计原则,帮助你定义灵活的和可维护的软件。该 MoveCustomer 例如侵犯至少两种这些规则:

的单一职责原则。类持有 MoveCustomer 方法不仅移动客户,而且还能测量它需要做手术的时间。换句话说,它具有多个责任。你应该提取测量到它自己的类。 的开 - 闭原则(OCP)。该系统的行为应该能够在不改变code任何现有生产线被改变。当你还需要异常处理(第三责任),你(再次)必须改变 MoveCustomer 方法,这是违反了OCP的。

除了违反了SOLID原则我们肯定违反了干原则在这里,这基本上说,code重复是坏的,mkay。

解决这个问题的方法是提取记录到它自己的类和允许类来包装的原班:

  //真实的东西
公共类MoveCustomerCommand
{
    公共虚拟无效MoveCustomer(INT客户ID,地址newAddress)
    {
        //实际操作
    }
}

//该装饰
公共类MeasuringMoveCustomerCommandDecorator:MoveCustomerCommand
{
    私人只读MoveCustomerCommand装饰;
    私人只读ILogger记录;

    公共MeasuringMoveCustomerCommandDecorator(
        MoveCustomerCommand装饰,ILogger记录仪)
    {
        this.decorated =装饰;
        this.logger =记录;
    }

    公众覆盖无效MoveCustomer(INT客户ID,地址newAddress)
    {
        VAR手表= Stopwatch.StartNew();

        this.decorated.MoveCustomer(客户ID,newAddress);

        this.logger.Log(MoveCustomer在执行+
            watch.ElapsedMiliseconds +毫秒。);
    }
}
 

通过缠绕真实情况的装饰,你现在可以添加此测量行为的类,没有系统的任何其他部分改变:

  MoveCustomerCommand命令=
    新MeasuringMoveCustomerCommandDecorator(
        新MoveCustomerCommand(),
        新DatabaseLogger());
 

在previous例子也不过只是解决问题(只固体部分)的一部分。当编写C如上图所示的$ C $,你必须定义装饰为系统中的所有操作,而你最终会与像装饰 MeasuringShipOrderCommandDecorator MeasuringCancelOrderCommandDecorator MeasuringCancelShippingCommandDecorator 。再这导致了大量的重复的code(违反了DRY原则),仍然需要写code为系统中的每一个操作。现在缺少的这里是过度使用的情况下在系统中通用的抽象。现在缺少的是一个 ICommandHandler< TCommand> 接口

让我们来定义这个接口:

 公共接口ICommandHandler< TCommand>
{
    无效执行(TCommand命令);
}
 

和我们的存储 MoveCustomer 方法的方法参数到它自己(参数对象)类叫做 MoveCustomerCommand

 公共类MoveCustomerCommand
{
    公众诠释客户ID {获得;组; }
    公共广播NewAddress {获得;组; }
}
 

和让我们把在一个类中的 MoveCustomer 法的行为,实现 ICommandHandler< MoveCustomerCommand>

 公共类MoveCustomerCommandHandler:ICommandHandler< MoveCustomer>
{
    公共无效执行(MoveCustomer命令)
    {
        诠释客户ID = command.CustomerId;
        VAR newAddress = command.NewAddress;
        //实际操作
    }
}
 

这看起来很奇怪,但因为我们现在对用例的一般抽象,我们可以重写我们的装饰如下:

 公共类MeasuringCommandHandlerDecorator< TCommand>
    :ICommandHandler< TCommand>
{
    私人ICommandHandler< TCommand>装饰;
    私人ILogger记录;

    公共MeasuringCommandHandlerDecorator(
        ICommandHandler< TCommand>装饰,ILogger记录仪)
    {
        this.decorated =装饰;
        this.logger =记录;
    }

    公共无效执行(TCommand命令)
    {
        VAR手表= Stopwatch.StartNew();

        this.decorated.Execute(命令);

        this.logger.Log(typeof运算(TCommand).Name点+,在执行+
            watch.ElapsedMiliseconds +毫秒。);
    }
}
 

这个新的 MeasuringCommandHandlerDecorator< T> 看起来很像 MeasuringMoveCustomerCommandDecorator ,但是这个类可以重复使用的所有系统中的命令处理程序:

  ICommandHandler< MoveCustomerCommand> handler1 =
    新MeasuringCommandHandlerDecorator< MoveCustomerCommand>(
        新MoveCustomerCommandHandler(),
        新DatabaseLogger());

ICommandHandler< ShipOrderCommand> handler2 =
    新MeasuringCommandHandlerDecorator< ShipOrderCommand>(
        新ShipOrderCommandHandler(),
        新DatabaseLogger());
 

此方式,将是非常非常容易增加横切关注到系统中。这是很容易地创建一个方便的方法在成分根,可以换任何创建命令处理程序的系统适用的命令处理程序。例如:

  ICommandHandler< MoveCustomerCommand> handler1 =
    装点(新MoveCustomerCommandHandler());

ICommandHandler< ShipOrderCommand> handler2 =
    装点(新ShipOrderCommandHandler());

私有静态ICommandHandler< T>装饰< T>(ICommandHandler< T> decoratee)
{
    返回
        新MeasuringCommandHandlerDecorator< T>(
            新DatabaseLogger(),
                新ValidationCommandHandlerDecorator< T>(
                    新ValidationProvider(),
                    新AuthorizationCommandHandlerDecorator< T>(
                        新AuthorizationChecker(
                            新AspNetUserProvider()),
                        新TransactionCommandHandlerDecorator< T>(
                            decoratee))));
}
 

如果您的应用程序启动但是成长,它可以让痛苦来引导这一切,没有一个容器。尤其是当您装饰有泛型类型的限制。

但有一个陷阱,但。它似乎是更难以配置装饰用Unity和Windsor. Autofac(例如)和简单注射器(的

 
精彩推荐
图片推荐