正しく名前を付けているかどうかわからない(つまり、ネストされたインターフェイスの実装)。ただし、ネストされたインターフェイスの実装よりも動的プロキシを使用する利点がわかりません。以下のサンプルコードよりも動的プロキシの方が優れていますか?次のサンプルコードは、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();
}
}
}