C# 使用fluent界面和builder模式

C# 使用fluent界面和builder模式,c#,.net-core,fluent,C#,.net Core,Fluent,我试图通过创建下面的person builder对象来理解fluent builder模式。我已经编写了我想要使用的代码,但是在实现它时遇到了问题。我的问题如下: 调用HavingJob()时,应创建一个新的作业,该作业可仅使用适用于作业的方法进行配置,并最终添加到人员的Jobs集合中。感觉应该返回它,以便对其调用其他流畅的作业方法。暂时不知道如何实现,允许在该级别或更高级别进行链接 在实现IJobBuilder方法时,我无法访问他们在HavingJob()方法中创建的特定作业,因为我需要返回I

我试图通过创建下面的person builder对象来理解fluent builder模式。我已经编写了我想要使用的代码,但是在实现它时遇到了问题。我的问题如下:

  • 调用
    HavingJob()
    时,应创建一个新的作业,该作业可仅使用适用于作业的方法进行配置,并最终添加到人员的
    Jobs
    集合中。感觉应该返回它,以便对其调用其他流畅的作业方法。暂时不知道如何实现,允许在该级别或更高级别进行链接
  • 在实现
    IJobBuilder
    方法时,我无法访问他们在
    HavingJob()
    方法中创建的特定作业,因为我需要返回
    IJobBuilder
    以将fluent方法限制为仅与作业相关的方法。拥有job()的诀窍是什么,以便这些特定的作业方法可以在允许链接的情况下对特定的作业进行操作
  • 一旦我走上以
    IJobBuilder
    结尾的流畅路径,我就不能再调用
    Build()
    HavingJob()
    来添加其他作业。这个问题的答案是要有一个独立的
    IJobBuilder
    实现,它继承自
    PersonBuilder
  • 公共类人物
    {
    公共字符串名称{get;set;}
    公共列表作业{get;set;}
    公共列表电话{get;set;}
    }
    公用电话
    {
    公共字符串编号{get;set;}
    公共字符串用法{get;set;}
    }
    公开课工作
    {
    公共字符串CompanyName{get;set;}
    公共整数{get;set;}
    }
    班级计划
    {
    静态void Main(字符串[]参数)
    {
    var p=人事构建器
    .Create()
    .WithName(“我的名字”)
    .拥有电话(“222-222-2222”)
    .WithUsage(“单元格”)
    .HavingJob()
    .WithCompanyName(“第一家公司”)
    .带天平(100)
    .HavingJob()
    .公司名称(“第二家公司”)
    .带天平(200)
    .Build();
    WriteLine(JsonConvert.SerializeObject(p));
    }
    }
    公共类PersonBuilder:IJobBuilder
    {
    受保护人;
    public PersonBuilder(){Person=new Person();}
    公共静态PersonBuilder Create()=>新建PersonBuilder();
    带名称的公共PersonBuilder(字符串名称)
    {
    Person.Name=姓名;
    归还这个;
    }
    公共PersonBuilder拥有电话(字符串电话号码)
    {
    //需要手机的实例吗
    归还这个;
    }
    public PersonBuilder WithUsage(字符串phoneUsage)
    {
    //需要手机的实例吗
    归还这个;
    }
    公共IJobBuilder HavingJob()
    {
    //需要在这里创建作业并返回它,以便IJobBuilder方法在特定实例上工作,对吗?
    归还这个;
    }
    公共人物构建()=>人物;
    带有companyName(字符串companyName)的公共IJobBuilder
    {
    //如果此处没有作业实例,如何设置公司名称
    job.CompanyName=CompanyName;
    归还这个;
    }
    公共IJobBuilder带余额(整数金额)
    {
    //如果这里没有具体的工作实例,我该如何设置工资
    工作。工资=金额;
    归还这个;
    }
    }
    公共接口IJobBuilder
    {
    IJobBuilder with companyName(字符串companyName);
    IJobBuilder和salary(内部工资);
    }
    
    单一责任原则(SRP)和关注点分离(SoC) 工作构建者应该负责构建工作

    public interface IJobBuilder {
        IJobBuilder WithCompanyName(string companyName);
        IJobBuilder WithSalary(int salary);
    }
    
    public class JobBuilder : IJobBuilder {
        private readonly Job job;
    
        public JobBuilder() {
            job = new Job();
        }
    
        public IJobBuilder WithCompanyName(string companyName) {
            job.CompanyName = companyName;
            return this;
        }
    
        public IJobBuilder WithSalary(int amount) {
            job.Salary = amount;
            return this;
        }
    
        internal Job Build() => job;
    }
    
    建造人员应负责建造人员

    public class PersonBuilder {
        protected Person Person;
        
        private PersonBuilder() { Person = new Person(); }
    
        public static PersonBuilder Create() => new PersonBuilder();
    
        public PersonBuilder WithName(string name) {
            Person.Name = name;
            return this;
        }
    
        public PersonBuilder HavingJob(Action<IJobBuilder> configure) {
            var builder = new JobBuilder();
            configure(builder);
            Person.Jobs.Add(builder.Build());
            return this;
        }
    
        public Person Build() => Person;
    
    }
    

    感谢您的快速响应,这确实会起作用。这种方法是否总是需要为任何类型创建一个完全独立的生成器,而这些类型不是person上的值类型。拿一个简单的电话号码列表,甚至是一组昵称(我编辑了我的原始帖子)。我只想在列表中添加一个电话号码,可以选择设置电话号码使用情况。您是否会创建昵称生成器和电话号码生成器,以便限制fluent API方法选项?我在一个集合中苦苦挣扎,在这个集合中,每个项都可以有自己的一组特定的流体方法调用。@Geekn在这种情况下,使用手机,您可以始终传递函数
    PersonBuilder HavingPhone(字符串编号,字符串用法){..}
    似乎我已经看到了一些使用泛型、继承或流体接口与faceted builder的方法。我当然可以,但我将该示例进行了一些扩展,以显示我正在努力解决的真正问题。HasPhone.WithCountryCode().CanUseForMarketing()等…如何在一个属性上设计流体,该属性是一个项目集合,其中每个项目都有自己的方法,这本质上是我问题的关键。我也看到过建筑商彼此继承。或者有些为每个路径都有一个接口。
    public class PersonBuilder {
        protected Person Person;
        
        private PersonBuilder() { Person = new Person(); }
    
        public static PersonBuilder Create() => new PersonBuilder();
    
        public PersonBuilder WithName(string name) {
            Person.Name = name;
            return this;
        }
    
        public PersonBuilder HavingJob(Action<IJobBuilder> configure) {
            var builder = new JobBuilder();
            configure(builder);
            Person.Jobs.Add(builder.Build());
            return this;
        }
    
        public Person Build() => Person;
    
    }
    
    class Program {
        static void Main(string[] args) {
            var p = PersonBuilder
                .Create()
                    .WithName("My Name")
                    .HavingJob(builder => builder
                        .WithCompanyName("First Company")
                        .WithSalary(100)
                    )
                    .HavingJob(builder => builder
                        .WithCompanyName("Second Company")
                        .WithSalary(200)
                    )
                .Build();
    
            Console.WriteLine(JsonConvert.SerializeObject(p));
        }
    }