Builder类只需要创建其构建的单个实例

问题描述 投票:0回答:1

我正在尝试创建一个构建一个Person对象实例的构建器类。问题是它创建了三个Person对象。我知道这一点,因为它触发构造函数三次(它向控制台写入三次)。我该怎么做才能创造一个呢?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using static System.Console;

namespace DotNetDesignPatternDemos.Creational.BuilderFacets
{
  public class Person
  {
    // address
    public string StreetAddress, Postcode, City;

    // employment
    public string CompanyName, Position;

    public int AnnualIncome;

    public Person()
    {
      Console.WriteLine("Person instanced");
    }

    public override string ToString()
    {
      return $"{nameof(StreetAddress)}: {StreetAddress}, {nameof(Postcode)}: {Postcode}, {nameof(City)}: {City}, {nameof(CompanyName)}: {CompanyName}, {nameof(Position)}: {Position}, {nameof(AnnualIncome)}: {AnnualIncome}";
    }
  }

  public class PersonBuilder  
  {
    protected Person person = new Person();
    public PersonAddressBuilder Lives => new PersonAddressBuilder(person);
    public PersonJobBuilder Works => new PersonJobBuilder(person);

    public Person Build()
    {
      return this.person;
    }
  }

  public class PersonJobBuilder : PersonBuilder
  {
    public PersonJobBuilder(Person person)
    {
      this.person = person;
    }

    public PersonJobBuilder At(string companyName)
    {
      person.CompanyName = companyName;
      return this;
    }

    public PersonJobBuilder AsA(string position)
    {
      person.Position = position;
      return this;
    }

    public PersonJobBuilder Earning(int annualIncome)
    {
      person.AnnualIncome = annualIncome;
      return this;
    }
  }

  public class PersonAddressBuilder : PersonBuilder
  {
    public PersonAddressBuilder(Person person)
    {
      this.person = person;
    }

    public PersonAddressBuilder At(string streetAddress)
    {
      person.StreetAddress = streetAddress;
      return this;
    }

    public PersonAddressBuilder WithPostcode(string postcode)
    {
      person.Postcode = postcode;
      return this;
    }

    public PersonAddressBuilder In(string city)
    {
      person.City = city;
      return this;
    }

  }

  public class Demo
  {
    static void Main(string[] args)
    {
      var pb = new PersonBuilder();
      Person person = pb
        .Lives
          .At("123 London Road")
          .In("London")
          .WithPostcode("SW12BC")
        .Works
          .At("Fabrikam")
          .AsA("Engineer")
          .Earning(123000).Build();

      WriteLine(person);
    }
  }
}

结果是

Person instanced
Person instanced
Person instanced
StreetAddress: 123 London Road, Postcode: SW12BC, City: London, CompanyName: Fab
rikam, Position: Engineer, AnnualIncome: 123000

基本上,它需要为每个Builder实例创建一个Person实例。

我不认为Singleton是解决方案,因为我不需要全局可访问的对象。

c# oop builder
1个回答
2
投票

每个衍生的建造者都继承自PersonBuilder,所以当你新建一个PersonJobBuilder时,你也是新来的Person

var pb = new PersonBuilder();

public PersonAddressBuilder Lives => new PersonAddressBuilder(person);
public PersonJobBuilder Works => new PersonJobBuilder(person);

因此,每个新的一个Person,三个实例。

编辑

快速解决方法是让你的Person实例静态,只有一个存在。从技术上讲,你的教程代码确实有用,它不能保证创建一个人对象,但你总是对当前人进行操作。

public class Person
{
    // address
    public string StreetAddress, Postcode, City;

    // employment
    public string CompanyName, Position;

    public int AnnualIncome;

    public Person()
    {
        Console.WriteLine("Person instanced");
    }

    public override string ToString()
    {
        return $"{nameof(StreetAddress)}: {StreetAddress}, {nameof(Postcode)}: {Postcode}, {nameof(City)}: {City}, {nameof(CompanyName)}: {CompanyName}, {nameof(Position)}: {Position}, {nameof(AnnualIncome)}: {AnnualIncome}";
    }
}

public class PersonBuilder
{
    protected static Person _person = new Person();
    public PersonAddressBuilder Lives => new PersonAddressBuilder(_person);
    public PersonJobBuilder Works => new PersonJobBuilder(_person);

    public Person Build()
    {
        return _person;
    }
}

public class PersonJobBuilder : PersonBuilder
{
    public PersonJobBuilder(Person person)
    {
        _person = person;
    }

    public PersonJobBuilder At(string companyName)
    {
        _person.CompanyName = companyName;
        return this;
    }

    public PersonJobBuilder AsA(string position)
    {
        _person.Position = position;
        return this;
    }

    public PersonJobBuilder Earning(int annualIncome)
    {
        _person.AnnualIncome = annualIncome;
        return this;
    }
}

public class PersonAddressBuilder : PersonBuilder
{
    public PersonAddressBuilder(Person person)
    {
        _person = person;
    }

    public PersonAddressBuilder At(string streetAddress)
    {
        _person.StreetAddress = streetAddress;
        return this;
    }

    public PersonAddressBuilder WithPostcode(string postcode)
    {
        _person.Postcode = postcode;
        return this;
    }

    public PersonAddressBuilder In(string city)
    {
        _person.City = city;
        return this;
    }

}

public class Demo
{
    static void Main(string[] args)
    {
        var pb = new PersonBuilder();
        Person person = pb
          .Lives
            .At("123 London Road")
            .In("London")
            .WithPostcode("SW12BC")
          .Works
            .At("Fabrikam")
            .AsA("Engineer")
            .Earning(123000).Build();

        WriteLine(person);
        Console.ReadLine();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.