Not sure if i'm naming it correctly (i.e. nested interface implementations). However I do not understand the benefit of using dynamic proxy over nested interface implementations. How is dynamic proxy better than doing what the sample code below does? Is the following sample code in some way more limiting that the interceptor pattern used in DynamicProxy?
UPDATE I understand what cross-cutting concerns are and how DynamicProxy makes maintaining these situations easier. Things like logging exceptions are independent of what the actual code being executed is doing. This example is not universal in nature like the logging example. Eat is how a cookie you eat a cookie. It should not be concerned with when you should eat it. A less contrived example would be a query service that determines if it should call an implementation that uses a local storage, or call an implementation that makes a network call for specific queries. Based on if it has received a message on the bus for an item update contained in the local storage. How would using a DynamicProxy interceptor in cases like these be advantageous for code maintenance?
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();
}
}
}