Класс Builder должен создать только один экземпляр того, что его строит - PullRequest
0 голосов
/ 10 апреля 2019

Я пытаюсь создать класс построителя, который будет создавать отдельный экземпляр объекта 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 - это решение, так как мне не нужен глобально доступный объект.

1 Ответ

2 голосов
/ 10 апреля 2019

Каждый производный построитель наследует от 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();
    }
}
...