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.
精彩评论