We have a model (IPayableModel) with a boolean property indicating that a user may or may not pay for the item. A set of specifications defining criteria that would disqualify the model from payment are grouped into a composite specification and applied to each model in the list. If any of the specifications are satisfied by the model, the pay action is not available.

Our challenge now is that we need to capture the specification that caused the failure so that we can present a particular message to the user.

A simplistic example: if the model has its CanPay property set to false because the composite specification determined that there is no money owed on the model, we would tell the user that they cannot pay because there is no balance.

In Fowler's article on the specification pattern (http://www.martinfowler.com/apsupp/spec.pdf), he mentions (pg. 17) the concept of a "Partially Fulfilled Specification", which implements a remainderUnsatisfiedBy property. This seems pretty darn close to what I'm looking for, but I'm not sure I understand his intent. I would guess it might look something like this (at least for our use-case):

public class PartiallyFulfilledCompositeSpecification<T> : CompositeSpecification<T>
    public ISpecification<T> RemainderUnfilledBy { get; }

Which (in our case) would hold the type of ISpecification that was satisfied by the model (e.g. ZeroBalanceSpecification).

I don't think that this is exactly Fowler's intended use, though, and I don't want to confuse any future maintainers by deviating too much from a specific pattern.

Is there a better (read: established/common) way to inform the client of a CompositeSpecification which individual specifications were satisfied or not satisfied by the provided model?

  • 1
    How well does this scheme satisfy your software's functional and non-functional requirements for behavior, performance, maintainability, extensibility and so forth? – Robert Harvey Apr 18 '15 at 4:08
  • @RobertHarvey, it's an improvement (in all cases) over the previous solution which this scheme is replacing. Our goals were: retain the ability for our customers to define varying criteria, reduce code duplication, and get rid of the single gigantic static virtual method that was previously responsible for doing all of the checks (as well as providing out parameters for the messages I refer to above). This also enables us to write specifications that can be constructed at run-time, which should reduce the amount of custom code (stored in a separate assembly) needed by our customer base. – Pete Scott Apr 18 '15 at 14:42
  • 1
    Then I think you've answered your own question. – Robert Harvey Apr 18 '15 at 14:43
  • @RobertHarvey Ah. I see what you did there. Fair enough. =] – Pete Scott Apr 18 '15 at 14:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.