2

I know that design patterns are set by the design and not by specific code yet sometimes I get concerned that I bent the pattern too much and no longer follow the design.

For Example Specification Pattern looks like this:

 public interface ISpecification<T>
{
    bool IsSatisfiedBy(T candidate);
}

But to me this isn't very readable:

 _customerAccountIsActive
.And(_hasReachedRentalThreshold)
.And(_customerAccountHasLateFees)
.IsSatisfiedBy(this); 

So I changed it to pass the candidate inside the constructor:

public abstract class Specification<TEntity> : ISpecification<TEntity>
{
    protected TEntity _candidate;

    public Specification(TEntity candidate)
    {
        _candidate = candidate;
    }

    public bool IsSatisfied()
    {
        return IsSatisfiedBy(_candidate);
    }
}

And I even Overloaded The bool operator so I can write something like this:

_customerAccountIsActive 
&& _customerAccountHasLateFees
&& _hasReachedRentalThreshold

Now I'd like to know from someone more experienced with design patterns whether I'm twisting this too much and what are the risks I should be aware of.

Andrej K
  • 1,794
  • 1
  • 17
  • 37

1 Answers1

1

You can find the similar question here How to adapt the Specification pattern to evaluate a combination of objects?. I have same issue with you and there is 2 adaptation I can think.

My problem is comparing 2 object of 2 different type of TEntity in one specification.

Right now, I'm trying to add the second entity to the IsSatisfied(T candidate) like this: IsSatisfied(T firstCandidate, K secondCandidate)

So the Specification will be come Specification, but I think I will lose the ​ability of combine the Specification with Specification.

So far, I haven't had any good idea about adding second candidate into specification.

There is 2 workarounds that I can think:

  1. Using a parameter object and use this object as an candidate object:

    public class ParameterObject<T,K>
    {
      public T FirstObject { get; set; }
      public K SecondObject { get; set; {
    }
    
    
    public SomeSpecification: Specification<ParameterObject<Order, Customer>>
    
    public bool IsSatisfied(ParameterObject candidate)
    {
       // do some check between order and customer candidates.
    }
    
  2. Using contructor injection:

    public class OutOfRangeOrderSpeficiation: Specification<Order>
    {
       private ICriteria _criteria;
    
        public OutOfRangeOrderSpeficiation(ICriteria criteria)
        {
           _criteria = criteria;
        }
    
        public bool IsSatisfied(Order candidate)
        {
          // comparing between order candidate and _criteria.
          return false;
        }
    }
    
Community
  • 1
  • 1
Vu Nguyen
  • 3,605
  • 3
  • 22
  • 34