繁体   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