簡體   English   中英

流利的生成器模式返回根類型

[英]Fluent Builder pattern which returns root type

我想使用以下調用鏈為我的目的創建構建器:

User user = new CommonBuilder(new UserNode()).Root //generic parameter, currently is User
    .Group.Group.Folder.Build();

這是我使用的代碼:

public abstract class AbstractNode
{
    public Guid Id { get; } = Guid.NewGuid();
}

public abstract class AbstractNode<T> where T : AbstractNode<T>
{

}

public class CommonBuilder<T> where T : AbstractNode<T>
{
    public T Root { get; private set; }
    public CommonBuilder(T root)
    {
        Root = root;
    }
}

public class UserNode : AbstractNode<UserNode>
{
    private GroupNode _group;
    public GroupNode Group
    {
        get
        {
            if (_group is null)
            {
                _group = new GroupNode();
            }
            return _group;
        }
    }
}

public class GroupNode : AbstractNode<GroupNode>
{
    private GroupNode _group;
    public GroupNode Group
    {
        get
        {
            if (_group is null)
            {
                _group = new GroupNode();
            }
            return _group;
        }
    }

    private FolderNode _folder;
    public FolderNode Folder
    {
        get
        {
            if (_folder is null)
            {
                _folder = new FolderNode();
            }
            return _folder;
        }
    }
}

public class FolderNode : AbstractNode<FolderNode>
{

}

問題出在Build()方法中,該方法需要從CommonBuilder而不是File返回Root

我必須將Build()方法放在哪里,該方法必須始終在鏈的末尾調用,該方法返回生成器的Root

如果需要制作一條鏈,則應該返回相同的對象,即使另一個接口檢查帶有Fluent接口的實施生成器的第一第二個示例

我已嘗試實現您的情況以適合該角色,請檢查它是否適合您的要求:

public interface IGroup<T>
{
    IGroup<T> Group { get; }
    IFolder<T> Folder { get; }
}
public interface IFolder<T>
{
    T Build();
}

Builder實現所有必需的接口。 並在每次調用中返回自身。 通常,您可以將Build方法放入Build器本身,並在鏈執行結束后分別調用它。

public class CommonBuilder<T> : IGroup<T>, IFolder<T> where T: INode, new()
{
    private T _root = new T();

    public T Build()
    {
        return _root;
    }

    public IGroup<T> Group
    {
        get
        {
            _root.MoveToGroup();
            return this;
        }
    }

    public IFolder<T> Folder
    {
        get
        {
            _root.MoveToFolder();
            return this;
        }
    }
}

由於泛型,需要對通過INode接口完成的泛型參數設置一些限制

public interface INode
{
    void MoveToGroup();
    void MoveToFolder();
}

測試用戶對象

public class User : INode
{
    public StringBuilder Path { get; } = new StringBuilder();

    public void MoveToFolder()
    {
        Path.AppendLine("Folder");
    }

    public void MoveToGroup()
    {
        Path.AppendLine("Group");
    }
    public override string ToString()
    {
        return Path.ToString();
    }
}

通話看起來像

var user = new CommonBuilder<User>().Group.Group.Folder.Build();

編輯

也許作為第一步,它有必要擺脫Fluent接口並僅使用Builder來實現邏輯:

public class FolderNode : INode<Folder>
{
    private readonly Folder _folder = new Folder();
    public Folder Build()
    {
        return _folder;
    }
    public void AppendGroup()
    {
        _folder.Path.AppendLine("Folder Group");
    }
    public void AppendFolder()
    {
        _folder.Path.AppendLine("Folder Folder");
    }
}

public class UserNode : INode<User>
{
    private readonly User _user = new User();
    public User Build()
    {
        return _user;
    }
    public void AppendGroup()
    {
        _user.Path.AppendLine("Group");
    }
    public void AppendFolder()
    {
        _user.Path.AppendLine("Folder");
    }
}

public class CommonBuilder<T, TNode> where TNode : INode<T>
{
    private readonly TNode _root;

    public CommonBuilder(TNode root)
    {
        _root = root;
    }

    public T Build()
    {
        return _root.Build();
    }

    public CommonBuilder<T, TNode> Group {
        get
        {
            _root.AppendGroup();
            return this;
        }
    }

    public CommonBuilder<T, TNode> Folder {
        get
        {
            _root.AppendFolder();
            return this;
        }
    }

}

public interface INode<out T>
{
    T Build();
    void AppendGroup();
    void AppendFolder();

}

public class Folder
{
    public StringBuilder Path { get; } = new StringBuilder();

    public override string ToString()
    {
        return Path.ToString();
    }
}

public class User
{
    public StringBuilder Path { get; } = new StringBuilder();

    public override string ToString()
    {
        return Path.ToString();
    }
}

用法:

var user = new CommonBuilder<User, UserNode>(new UserNode()).Group.Group.Folder.Build();
var folder = new CommonBuilder<Folder, FolderNode>(new FolderNode()).Group.Folder.Group.Folder.Build();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM