Question

I'm trying to do a simple implementation of the Specification pattern in my domain layer.

If I have a static class full of specifications like this:

public static class FooSpecifications
{
  public static Func<Foo, bool> IsSuperhuman
  {
    get
    {
      return foo => foo.CanShootLasersOutOfItsEyes && foo.CanFly;
    }
  }
}

Then I can do marvellous things like this:

IEnumerable<Foo> foos = GetAllMyFoos();
var superFoos = foos.Where(FooSpecifications.IsSuperhuman);

I can also add bool method to Foo to determine if a particular instance meets a specification:

public bool Meets(Func<Foo, bool> specification)
{
  return specification.Invoke(this);
}

Given that Foo, like all my domain entities, extends DomainObject, is there a way I can put a generic implementation of Meets() into the DomainObject to save me implementing Meets() separately in every entity?

Was it helpful?

Solution

Something like this...

    public abstract class DomainObj<T> // T - derived type
        where T : DomainObj<T>
    {
        public bool Meets(Func<T, bool> specification)
        {
            return specification.Invoke((T) this);
        }
    }

    public class Foo : DomainObj<Foo> {}

    public class Bar : DomainObj<Bar> {}       

        Func<Foo, bool> foospec = x => true;
        Func<Bar, bool> barspec = x => true;

        var foo = new Foo();
        var bar = new Bar();
        foo.Meets(foospec);
        foo.Meets(barspec); // won't compile because of mismatched types of spec and object instance

EDIT

Maybe it will be better to translate Meet method to extension. This will remove need in type parameter.

    public abstract class DomainObj
    {
    }

    public static class DomainObjExtensions
    {
        public static bool Meets<T>(this T obj, Func<T, bool> f)
            where T : DomainObj
        {
            return f(obj);
        }
    }

    public class Foo : DomainObj {}

    public class Bar : DomainObj {}

    Func<Foo, bool> foospec = x => true;
    Func<Bar, bool> barspec = x => true;

    var foo = new Foo();
    var bar = new Bar();
    foo.Meets(foospec);
    foo.Meets(barspec); // error
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top