开发者

C# - Complex variable-assignment

i have a class Row. This class should have a Content-property. Currently the content is of type: List<IRowContent>

(IRowContent is a interface)

Other classes Column and TextContent, ImageContent implements the interface IRowContent.

I can add now some Columns to the list or real "content" (Text or a image).

But you can also add columns and text/image. But if a row contains text/image i开发者_如何学JAVAt should not contain another item.

How can i design my class-structure to support this?

Edit: some additionals infos: I want to build a layout with "fluent interfaces" http://en.wikipedia.org/wiki/Fluent_interface

And my idee is to prevent wrong use by intellisense of VisualStudio.

Here my classes: The Layout have a column-list.

class Layout
   {
      //Attributes
      public Color Background { get; set; }
      public List<Column> Columns { get; set; }
      public uint Margin { get; set; }

      public Layout AddColumn(Column c)
      {
         return null;
      }

      public Layout SetColumnList(List<Column> c)
      {
         return null;
      }
   }

The column has a list of content (IColumnContent). The column itself is from IRowContent.

class Column : IRowContent
   {
      public List<IColumnContent> Content { get; private set; }

      public Column AddToContent(IColumnContent obj)
      {
         return null;
      }

      public Column SetContent(List<IColumnContent> objs)
      {
         return null;
      }
   }

Same for Row with IRowContent:

   class Row : IColumnContent
   {
      public List<IRowContent> Content { get; private set; }

      //...
   }

ImageContent and TextContent implements both interfaces:

class TextContent : IRowContent, IColumnContent

class ImageContent : IRowContent, IColumnContent


If you declare the interface

interface IRowContent 
{
    bool SupportsOtherChildren{ get; }
    ...
}

class ImageContent : IRowContent
{
    public bool SupportsOtherChildren
    {
        get { return false; }
    }
}

class Column : IRowContent
{
    public bool SupportsOtherChildren
    {
        get { return true; }
    }
}

You can override a collection's insert and remove methods to support this behavior:

 class RowContentCollection : Collection<IRowContent>
    {
        bool containsSingleItem = false;
        protected override void InsertItem(int index, IRowContent item)
        {
            if (containsSingleItem)
                throw new InvalidOperationException("Collection contains an item that doesnt allow other items.");

            containsSingleItem = !item.SupportsOtherChildren;

            base.InsertItem(index, item);
        }

        protected override void RemoveItem(int index)
        {
            if (!this[index].SupportsOtherChildren)
                containsSingleItem = false;

            base.RemoveItem(index);
        }
    }


Just to summarize and to make sure I understand you correctly:

The Row class should contain a list of columns. Every column can be an object of type Column, TextContent or ImageContent. All three of these classes implement the RowContent interface (which in my opinion should be named IColumnContent...).

If that is correct, the restriction you're trying to impose (which I don't fully understand, to be honest) is not a matter of class design, but a matter of add/remove logic. I'd declare the Content property as

private List<RowContent> m_internalColumns;

public RowContent[] Columns { get { return m_internalColumns.ToArray(); }}

and create Add and Remove methods like the following (pseudo-code):

public void Add(RowContent column)
{
    if (adding column of type <typeof(column)> is allowed)
        m_internalColumns.Add(column);
}

public void Remove(RowContent column)
{
    m_internalColumns.Remove(column);
}


You could make your Row class generic:

class Row<T : IRowContent> {
    public List<T> Content { ... }
}

Then you can have a Row<Column>, which can only contain columns, or a Row<TextContent>, which can contain only text content. You can even have a Row<IRowContent> which allows for mixed content.

If you want a row that can only contain text and image content (but no columns), add an interfance IRealContent : IRowContent and have TextContent and ImageContent implement IRealContent. Then, a Row<IRealContent> can only contain text and images.


Abstract the details about the problem to the interface itself.

public interface IRowContent
{
      bool SupportsChildren { get; }

      // other properties
}

I would also introduce custom Add and Remove methods to the Row class that determine if the content being added can support additional content.


I would probably do one of 2 things. Either:

Instead of using Row.Content.Add() to add items, add a method to Row for adding content. Row.AddContent(iRowContent content); and put your 'logic' in that method for determining if whatever item can be added or not.

Or, instead of using a List, implement your own collection that inplements IList and write the Add() method in a way that contains your logic.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜