如何在复合 C# 中继承多个叶部分?

How to inherit multiple leaf parts in composite c#?

我正在用 c# 编写项目,其中包括不止一片叶子,我想知道这些节点是否应该继承复合而不是抽象 class。所以我有三片叶子:

  1. 段落
  2. 段落组
  3. 文档

段落继承抽象的文本 class class。现在,段落组 class 继承了段落 class,文档继承了段落组和段落。所以我想知道哪个 class 应该是我的复合材料?我正在考虑将复合材料放在 ParagraphComposite.cs class 中,然后使其看起来像这样:

段落和段落复合继承抽象class文本和段落组和文档继承段落复合class。

这是正确的做法吗?任何反馈将不胜感激。

让我们假设所有这些 class 都有共同的属性,例如 Text 属性,但也有不同的属性,例如其他类型的集合。为了不与Text属性冲突,我将抽象基称为classTextBase.

其他 classes 应该派生自 TextBase。例如。 Document 文档会有一个 ParagraphGroups 集合,但没有 Paragraphs 集合。即,它不能从具有 Paragraphs 集合的 ParagraphGroup 派生。

可能的方法:

public abstract class TextBase
{
    public const string LineSeparator = "\n";
    public const string ParagraphSeparator = "\r";
    public const string ParagraphGroupSeparator = "\v";

    public abstract string Text { get; set; }
}
public class Paragraph : TextBase
{
    public string[] Lines { get; set; } = new string[0];

    public override string Text
    {
        get => String.Join(LineSeparator, Lines);
        set => Lines = value.Split(new string[] { LineSeparator }, StringSplitOptions.None);
    }
}
public class ParagraphGroup : TextBase
{
    public Paragraph[] Paragraphs { get; set; } = new Paragraph[0];

    public override string Text
    {
        get => String.Join(ParagraphSeparator, Paragraphs.Select(p => p.Text));
        set => Paragraphs =
            value.Split(new string[] { ParagraphSeparator }, StringSplitOptions.None)
                .Select(s => new Paragraph { Text = s })
                .ToArray();
    }
}
public class Document : TextBase
{
    public ParagraphGroup[] ParagraphGroups { get; set; } = new ParagraphGroup[0];

    public override string Text
    {
        get => String.Join(ParagraphGroupSeparator, ParagraphGroups.Select(g => g.Text));
        set => ParagraphGroups =
            value.Split(new string[] { ParagraphGroupSeparator }, StringSplitOptions.None)
                .Select(s => new ParagraphGroup { Text = s })
                .ToArray();
    }
}

Documentclass不继承ParagraphGroup。相反,它包含 ParagraphGroup 的集合。为了简单起见,我使用了数组,但您也可以使用 List<T> 或创建您自己的特定集合类型。

注意当你获取或设置[=21=的Text属性时,这会递归调用[=24=的Text属性 ] 和 Paragraph,以便递归地连接或拆分元素。

您将获得文档中的第一行文本

string firstLine = document.ParagraphGroups[0].Paragraphs[0].Lines[0];

您将 AddRemove 之类的方法放在哪里?

一种可能是简单地依赖于您正在使用的集合的相应方法。示例:如果您正在使用 List<T> 集合,您可以简单地使用 List Methods(示例 paragraph.Lines.Add("hello");.

如果您想将这些方法直接添加到DocumentParagraph等,您将面临其中一些方法会采用不同类型的参数的问题。您可以使 TextBase 通用,但会失去赋值兼容性。最好声明一个通用接口。例如。

public interface ITextCollection<T>
{
    public abstract void Add(T item);
    public abstract void RemoveAt(int i);
}

Paragraph 的可能实现(假设您使用 List<string> 作为 Lines 属性。Paragraph 将实现 ITextCollection<string>

public void Add(string item)
{
    Lines.Add(item);
}

public void RemoveAt(int i)
{
    Lines.RemoveAt(i);
}

请注意,其他类型的实现方式不同,因为它们的集合名称不同并且属于另一种类型。例如。 ParagraphGroup 将实现 ITextCollection<Paragraph> 并且必须在 Paragraphs 集合中添加和删除。

这使您的 classes 成为复合体,因为它们本身不实现集合功能的细节,而是包含一个集合并将操作委托给这些集合。