+1  A: 

Actually, as the "root" node is a special case of node, maybe you need RootHtmlPageNode : HtmlPageNode.

Another idea: as you do not specify what is the difference between a "root" and normal node, maybe just a flag in node specifying if it is root or not also will be a good design.

EDIT: Per your clarification, there is no functional difference between normal and root node, so a simple flag should be enough (or property IsRootNode). If "root" node only supplies a styling data (or any other data for itself and it's children), then you can place this styling data in a separate structure/class and fetch it recursively (based on IsRootNode):

class Node
{
   private bool isRootNode;
   public bool IsRootNode;

   private StylingData stylingData;
   public StylingData StylingData
   {
      set
      {
         if (this.IsRootNode)
            this.stylingData = value;
         else
            throw new ApplicationException("The node is not root.");
      }
      get
      {
         if (this.IsRootNode)
            return this.stylingData;
         else
            return this.parent.StylingData;
      }
   }
}

This assumes, that each node has a reference to it's parent.

It become way beyond the question, as I do not know the exact design.

Sunny
Good point. I've added a root node clarification above.
Zack Peterson
+2  A: 

Use the the Composite Pattern.


With regard to your root nodes, are there differences in functionality or is the difference it entirely appearance? If the difference is appearance only I suggest you have an association with a separate Style class from your PageNode.

If there are differences in functionality AND you have lots of types of page then think about using the Decorator Pattern.

Martin Spamer
I need clarification. See my answer.
Zack Peterson
+1  A: 

I want the HtmlPageNode and CodePageNode classes to inherit either from PageNode or else from RootPageNode. Is that possible?

Yeah it's possible. You need to have HtmlPageNode and codePageNode have an object that will be an Abstract class that PageNode will inherit and RootPageNode too. In the constructor of HtmlPageNode and codePageNode you accept your new Abstract class that will be in your case PageNode OR RootPageNode. This way you have 2 differents classes with same methods but two differents object. Hope that help you!

Daok
A: 
Zack Peterson
Dont get too hung up on the is-a or has-a discussion... If one of them doesnt "feel" automatically right, then it doesnt matter, and just go with what works.
AviD
+2  A: 

As noted, the Composite Pattern may be a good solution.

If that doesn't work for you, it may be simpler - if appropriate - to define Root as an Interface, and apply that as needed.

Of course, that doesnt let you provide any implementation for Root...
If Root must have implementation, you can use the Decorator Pattern.

AviD
+1  A: 

Clarification: There are multiple root nodes and roots may have parent nodes. Each is the root of only a sub-tree that has distinct styling. Think of different, color-coded departments. (Perhaps root is a poor name choice. Suggestions?)

Root is a poor name choice because it's (somewhat ironically) accepted as explicitly the top level of a tree structure, because the tree starts where root comes out of the ground. Any node beyond that is a branch or leaf and not directly attached to the root.

A better name would be something like IsAuthoritativeStyleNode, IsCascadingStyleNode, IsStyleParentNode or instead qualify it: e.g. IsDepartmentRootNode. Giving things clear unambiguous names is one of things that drastically improves readability / easy understanding.

You can't really achieve what you want just via abstract base classes/inheritence. As per other suggestion(s), consider interfaces instead.

I'd also consider thinking about whether you're letting the database schema drive your client side class design too much. Not saying it needs changing in this case, but it should at least be thought about. Think about how you could factor out properties into separate tables referencing the common 'Node' table, and normalize them to minimize nulls and/or duplicated identical data.

Gordon Hartley
I'm still trying to zero in on a final architecture.I initially started with many small tables with almost zero nullalbe fields.http://stackoverflow.com/questions/56981/which-is-the-best-database-schema-for-my-navigation
Zack Peterson
And I learned about the LINQ to SQL IsDiscriminator property.http://stackoverflow.com/questions/57152/whats-the-best-way-to-handle-one-to-one-relationships-in-sql
Zack Peterson
But then I learned that LINQ to SQL only supports single table inheritence.http://stackoverflow.com/questions/67659/can-a-linq-to-sql-isdiscriminator-column-not-inherit
Zack Peterson