2
\$\begingroup\$

I'm building some code with an inheritance heirarchy, and I want to validate the resulting instances. At present I have a method in the base class can override to return a list of the problems (see the code).

My problem here is that this works, provided the inheriting classes remember to get the base results first, before returning their own. It works, but I'm not sure it's the best design?

using System;
using System.Linq;
using System.Collections.Generic;

namespace Query
{
    /// <summary>
    /// Root class with mehtod
    /// </summary>
    public abstract class baseClass
    {

        /// <summary>
        /// Is the object valid?
        /// </summary>
        /// <returns></returns>
        public bool IsValid()
        {
            return (!GetValidationIssues().Any());
        }

        /// <summary>
        /// Return list of validation issues
        /// </summary>
        /// <returns></returns>
        public virtual List<string> GetValidationIssues()
        {
            var result = new List<string>();
            if (Quantity < 0) result.Add("Quantity is invalid");
            return result;
        }

        public int Quantity { get; set; }
    }

    /// <summary>
    /// First child class, adds a new property and more validation
    /// </summary>
    public abstract class productBase : baseClass
    {
        public override List<string> GetValidationIssues()
        {
            // we must get any base results first!!
            var result = base.GetValidationIssues();
            // do checks for this class
            if (string.IsNullOrWhiteSpace(Name)) result.Add("Name not specified");
            return result;
        }

        public string Name { get; set; }
    }

    /// <summary>
    /// Final instance
    /// </summary>
    public class Product : productBase
    {
        public override List<string> GetValidationIssues()
        {
            // remember to get the base results first
            var result = base.GetValidationIssues();
            // do checks for this class
            if (Price <= 0) result.Add("Price is not valid");
            return result;
        }

        public decimal Price { get; set; }
    }

}
\$\endgroup\$
  • \$\begingroup\$ I don't think it is bad that the inheriting classes have to remember to call base.GetValidationIssues(). To help developers out you might want to put a comment on the base implementation to tell them that it is expected of them to call base.GetValidationIssues() though. \$\endgroup\$ – Joey Jan 19 '12 at 8:41
2
\$\begingroup\$

Here's a C# version using a cross of the template method pattern and the collector pattern. It'll pick up any issues from any derivative implementing the AddValidationIssues method.

public abstract class BaseClass
{
    public List<string> GetValidationIssues()
    {
        var result = new List<String>();
        if (Quantity < 0) result.Add("Quantity is invalid");  
        AddValidationIssues(result);
        return result;
    }

    protected virtual void AddValidationIssues(List<string> result)
    {
    }
}

public class ProductBase : BaseClass
{
    protected override void AddValidationIssues(List<string> result)
    {
        if (string.IsNullOrWhiteSpace(Name)) result.Add("Name not specified");   
    }
}

As a sidenote, I'd look for another name than "BaseClass". It doesn't say anything about what it does.

\$\endgroup\$
0
\$\begingroup\$

If you don't trust your client classes (maybe they don't call baseClass.GetValidationIssues) you can force it with the Template method pattern.

public abstract class BaseClass {

    public final List<String> getValidationIssues() {
        final List<String> issues = doGetBaseValidationIssues();
        final List<String> childIssues = doGetValidationIssues();
        issues.addAll(childIssues);
        return issues;
    }

    private List<String> doGetBaseValidationIssues() {
        return null;
    }

    protected abstract List<String> doGetValidationIssues();
}

It's Java code, but I suppose it's very similar in C# too. Note the final keyword on getValidationIssues, so client classes are unable to override it.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the reply. This would work for the base class and the final instance, but would not pick up the intermediate classes, but it's something to consider. \$\endgroup\$ – Quango Jan 18 '12 at 15:08
  • \$\begingroup\$ The intermediate classes also could implement this pattern but with a few levels it would look terrible. \$\endgroup\$ – palacsint Jan 18 '12 at 15:36
  • \$\begingroup\$ Funny thing about java and C#. In C# you can only override methods that have the virtual keyword, although you can hide non-virtual base methods using the new keyword. Completely opposite solution to the final keyword in java. :) (C# only have sealed classes for non-ineritables) \$\endgroup\$ – Lars-Erik Jan 23 '12 at 11:34

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.