Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm trying to make a case for not putting the structure in the parent BaseModule class I've shown below. I'm more for a Strategy Pattern, and minimizing inheritance in favor of has-a relationships, but I am not really sure of what principle of OOAD this pattern is breaking.

What principle of OOAD is this pattern breaking?

Potential Pattern:

public interface IStringRenderer
{
    string Render();
}

public class BaseModel : IRequestor
{
    public abstract void  Init();
    public abstract void Load();
}

public class BaseModule<TModel> : IStringRenderer where TModel : BaseModel
{
    public TModel Model { get; set; }

    public override string Render()
    {
        return
        string.Join(
            "",
            new string[]
            {
                "<header/>",
                "<main-container>",
                    "<side-nav>",
                        "<side-navigation/>",
                    "</side-nav>",
                    "<main-content>",
                        RenderMainContent(),
                    "</main-content>"
            });
    }

    public abstract string RenderMainContent();
}

public class MyModuleModel : BaseModel
{
    public List<int> Ints { get; set; }

            ...
}

public class MyModule : BaseModule<MyModuleModel>
{
    public override string RenderMainContent()
    {
        return
        string.Join(",", Model.Ints.Select(s => s.ToString()).ToArray());
    }
}

Preferred Pattern (duplicated some code to be clear):

public interface IStringRenderer
{
    string Render();
}

public class BaseModel : IRequestor
{
    public abstract void Init();
    public abstract void Load();
}

public class MyModuleModel : BaseModel
{
    public List<int> Ints { get; set; }

    ...
}

public class MyModule : IStringRenderer
{
    public MyModuleModel Model { get; set; }

    public MyModule(MyModuleModel model)
    {
        this.Model = model;
    }

    public override string Render()
    {
        return
        string.Join(
            "",
            new string[]
            {
                "<header/>",
                "<main-container>",
                    "<side-nav>",
                        "<side-navigation/>",
                    "</side-nav>",
                    "<main-content>",
                        RenderMainContent(),
                    "</main-content>"
            });
    }

    public string RenderMainContent()
    {
        return
        string.Join(",", Model.Ints.Select(s => s.ToString()).ToArray());
    }
}

There are parts of this pattern that I'm not trying to focus on, but instead I am thinking about where the 'structure', or the 'tags' are living. In the first example they live in the parent, but in the second example they have been pushed into the derived class.

Right now, the examples are pretty simple, but something like 'side-nav' could potentially get complicated, and may need to be controlled by the child anyway.

I feel the principle here is that I don't feel like the 'tag' structure shouldn't be in the parent class as in the first example. There are other things I've removed in my 'preferred version' -- namely the generics. (Any suggested reading on good/bad for that choice is welcome). Proponents of the first example's embedded structure like the fact that they can wield changes to large amounts of child classes. I feel offering the flexibility to derived classes is the way to go, and if there needs to be a parent that parent only offers functionality and cross-cutting features, but does not bottle up canned structure.

share|improve this question
    
Either approach is fine. The first approach is simpler and more people will be able to easily read and understand the code. The 2nd approach is for those who want to take their design to the next level. The claim is that it makes the code more reusable, which is true. However, at the same time this added flexibility tends to make the design more difficult for the typical developer to understand, particularly when this flexibility results in needing many additional classes. The end result, being that the typical developer won't want to use the more flexible design. Thus, which is more reusable? –  Dunk May 10 '13 at 15:24
1  
@Dunk Is there something to be said for writing code that "encourages" typical developers to become more flexible in their thinking? –  Amy Blankenship May 13 '13 at 16:39
    
@Amy:It depends. If you have some sway in getting the typical developers to use a certain approach then definately yes. Otherwise, your great design will be used, by just you. There really is just a relatively small percentage of developers who care enough about "better" ways to design software to put in the effort. The overwhelming majority are only concerned with getting something that appears to work as quickly as possible. If they are going to have to spend time learning new techniques or understanding an unfamiliar design, most will opt to reimplement in a way they already know. –  Dunk May 13 '13 at 18:14

2 Answers 2

You can have the best of both worlds. In the BaseModule<TModel> class, when you implement (you typed override there, which is not correct) the Render() method, you can flag it as virtual. This way, child classes that need a basic set of tags can simply use the base class Render(), while child classes with more peculiar needs may override it.

About the generics, you are not using them in the BaseModule<>... unless you are using it in a constructor (not shown) that initializes the Model property for all derived class maybe? In that case they have their use here, since they constrain the type you can pass in and they un-burden the derived classes from having to initialize it themselves. This is more like a "framework" approach, where an abstract base class is used only to provide common but overridable functionality to derived concrete classes.

share|improve this answer

Overview

It sounds similar to CommonClosurePrinciple, but happens on a class-and-methods level instead of a package-and-classes level. Namely,

--Classes-- (methods) within a released --component-- (a class) should share common closure. If one (method) needs to be changed, they all (methods) are likely to need to be changed. What affects one, affects all.

(I added the words in brackets.)

Also, the principle that can be gleaned from this code example is a weak one, meaning that it is not universally applicable. There are obviously cases where changes don't / shouldn't need to be concentrated into a single class!


In this particular question, the validity of this principle depends on whether the (1) HTML tags and (2) the model-to-string code are typically changed together when there is a change in model.

The Code

In both versions, MyModule is the place for the glue logic that exists between Model and IStringRenderer.Render().


In the first version, the HTML tags (<main-content>...</>) is a service provided by BaseModule.

  • If the same wrapping code is reused many times for many different models, this is a correct choice.
  • If each model ended up having to customize its HTML tags, then the BaseModule class in the first version will only get used once.

In the second version, both pieces of glue logic are contained in the leaf class (MyModule):

  • The conversion of integers (model) to a string, and
  • The HTML tags

Thus, the second version allow the model rendering and the HTML wrapping code to be changed together.


Opinion:

If it occurs to you that each model require different HTML tags, then I'd say that the first version is not sufficient, while the second version is. Otherwise, both versions are fine.

If one must look for a name for the principle, it would be along the line of "... methods that need to be changed together for the same reason (changing the model), would be nice to be placed into the same class."

(I emphasize "would be nice" because it is a weak principle, or, a rule-of-thumb and not a true principle.)

It sounds similar to CommonClosurePrinciple, but applied to a class-and-methods level instead of a package-and-classes level.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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