当关注点不是横切时,Castle Project'的DynamicProxy如何使代码更容易维护?

本文关键字:DynamicProxy 何使 代码 维护 更容易 关注点 Project Castle | 更新日期: 2023-09-27 18:19:10

不确定我是否正确命名它(即嵌套接口实现)。然而,我不明白使用动态代理比嵌套接口实现有什么好处。动态代理如何比下面的示例代码更好?下面的示例代码是否在某种程度上比DynamicProxy中使用的拦截器模式更有限制?

我理解什么是横切关注点,以及DynamicProxy如何使维护这些情况变得更容易。日志异常之类的事情与实际执行的代码是独立的。这个示例在本质上不像日志示例那样具有普遍性。吃是怎么饼干你吃饼干。当你应该吃时,它不应该与有关。一个不那么做作的例子是查询服务,它决定是否应该调用使用本地存储的实现,还是调用对特定查询进行网络调用的实现。基于它是否在总线上收到了本地存储中包含的项更新的消息。在这种情况下使用DynamicProxy拦截器对代码维护有什么好处?

using System;
using Castle.Windsor;
using Castle.MicroKernel.Registration;
 namespace ConsoleApplication19 {
public enum SmellsLike { Poo, YummyCookie }
public class Cookie {
    public SmellsLike SmellsLike { get; set; }
    public int Size { get; set; }
}
public interface IHaveCookies { 
    Cookie Eat(Cookie c);
    void OtherOperation(Cookie c);
}
// this would be the interceptor if implemented using DynamicProxy
// e.g. interceptor or decorator pattern
public class SmellService : IHaveCookies {
    IHaveCookies _;
    public SmellService(IHaveCookies implementation) {
        _ = implementation;
    }
    public Cookie Eat(Cookie c) {
        Console.WriteLine("Smelling cookie");
        // intercept call to Eat and don't call it if it smells like poo
        return c.SmellsLike == SmellsLike.Poo
            ? c
            : _.Eat(c);
    }
    // shows that i'm not intercepting this call
    void OtherOperation(Cookie c) {
        // do nothing
        _.OtherOperation(c);
    }
}
//This is the actual service implementation
public class EatService : IHaveCookies {
    public Cookie Eat(Cookie c) {
        Console.WriteLine("Eating cookie");
        var whatsLeft = NomNomNom(c);
        return whatsLeft;
    }
    Cookie NomNomNom(Cookie c) {
        c.Size--;
        return c;
    }
    public void OtherOperation(Cookie c) {
        // do something else
    }
}
   // shor program that uses windsor to wire up the interfaces
class Program {
    static void Main(string[] args) {
        var container = new WindsorContainer();
        container.Register(
            // interface implementation that is actually given when
            // container.Resolve is called
            Component.For<IHaveCookies>().ImplementedBy<SmellService>().Named("Smell"),
            // wiring up actual service implementation      
            Component.For<IHaveCookies>().ImplementedBy<EatService>().Named("Eat"),
            // this injects the interceptor into the actual service implementation
            Component.For<SmellService>().ServiceOverrides(ServiceOverride.ForKey("implementation").Eq("Eat")));

        // example usage
        var yummy = new Cookie { Size = 2, SmellsLike = SmellsLike.YummyCookie };
        var poo = new Cookie { Size = 2, SmellsLike = SmellsLike.Poo };
        var svc = container.Resolve<IHaveCookies>();
        Console.WriteLine("eating yummy");
        // EatService.Eat gets called, as expected
        svc.Eat(yummy);
        Console.WriteLine("eating poo");
        // EatService.Eat does not get called, as expected
        svc.Eat(poo);
        Console.WriteLine("DONE");
        Console.ReadLine();
    }
}
}

当关注点不是横切时,Castle Project'的DynamicProxy如何使代码更容易维护?

动态代理-拦截器-让你拦截调用任何接口。假设你想在任何接口的任何实现中拦截任何调用。您需要实现多少装饰器?它们都包含相同的代码,但在构造函数中接收不同的接口。而且他们必须实现所有的修饰接口的方法。这么多重复的代码。无聊而不干燥。

使用Castle,你可以实现IInterceptor一次,并使用它来做上面描述的事情。

public class LoggingInterceptor : IInterceptor  
{
    public void Intercept(IInvocation invocation)
    {
        // log method call and parameters
        try                                           
        {                                             
            invocation.Proceed();   
        }                                             
        catch (Exception e)              
        {                                             
            // log exception
            throw; // or sth else                
        }
    }                                             
}

回复你的UPDATE:这对我们没有好处。也许是错的。也许我不明白你的意思。也许这吗?

<>之前public class ServiceSelectingWhatCallToMake : IHaveCookies { public ServiceSelectingWhatCallToMake(IHaveCookies localCalls, IHaveCookies networkCalls) { // save in member variables } public SomeMethod() { if (somethingDescribingIShouldMakeLocalCall) this.localCalls.SomeMethod(); else this.networkCalls.SomeMethod(); } } 之前

那么应该是这个

<>之前public class ServiceThatDoesntKnowWhatCallItMakes { public ServiceSelectingWhatCallToMake(IHaveCookiesFactory factory) { // save in member variables } public SomeMethod() { var localOrNetwork = this.factory.Create(somethingDescribingWhatCallToMake) localCalOrNetwork.SomeMethod(); } } 之前

所以没有装饰器/拦截器的位置。像其他人描述的那样,我将使用拦截器来处理横切关注点——日志记录、审计、缓存、安全等等。

动态代理对于实现跨整个系统或子系统应用的行为方面非常有用。如果你有15个服务,每个服务有20个方法,它们需要应用相同的行为(安全检查、远程访问、日志记录等)。,或者嗅探——就像你的例子中一样),那么一个动态代理可以用来实现一次行为。使用委托,你可以达到同样的结果,但需要更多的样板代码(使用my numbers要多300倍)

重复的样板代码增加了进行更改所涉及的维护工作量,并且使某些类型的结构更改更加昂贵(并且不太可能发生)

动态代理也有一些缺点——代码比(单一使用)委托更复杂。性能特征也可能存在差异,这意味着在性能开销很大的极少数情况下,需要在性能和可维护性之间进行权衡。

我认为动态代理的理念是它非常适合横切关注点。底层对象图不会影响你试图插入的行为。例如每个函数的日志记录或策略执行