当关注点不是横切时,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,你可以实现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倍)
重复的样板代码增加了进行更改所涉及的维护工作量,并且使某些类型的结构更改更加昂贵(并且不太可能发生)
动态代理也有一些缺点——代码比(单一使用)委托更复杂。性能特征也可能存在差异,这意味着在性能开销很大的极少数情况下,需要在性能和可维护性之间进行权衡。
我认为动态代理的理念是它非常适合横切关注点。底层对象图不会影响你试图插入的行为。例如每个函数的日志记录或策略执行