Конструкторы - множество параметров или нет и использовать набор методов


На ваш взгляд, что является лучшим способом, чтобы построить объект с учетом двух приведенных ниже примерах:

Вариант 1: много параметров

private string firstname;
private string surname;
private Address homeAddress;
private PhoneNumber homeNumber;

public Person(string firstname, string surname, Address homeAddress, 
              PhoneNumber homeNumber)
{
    _firstname = firstname;
    _surname = surname;
    _homeAddress = homeAddress;
    _homeNumber = homeNumber;
}

public string getFirstname()
{
    return firstname;
}

public string getSurname()
{
    return surname;
}

public Address getAddress()
{
    return address;
}

public PhoneNumber getHomeNumber()
{
    return _homeNumber;
}

Вариант 2: без параметров и использование набора методов

private string firstname;
private string surname;
private Address homeAddress;
private PhoneNumber homeNumber;

public Person()
{
}

public string getFirstname()
{
    return firstname;
}
public void setFirstname(String value)
{
    firstname = value;
}

public string getSurname()
{
    return surname;
}
public void setSurname(String value)
{
    surname = value;
}

public Address getAddress()
{
    return address;
}
public void setAddress(Address value)
{
    address = value;
}

public PhoneNumber getHomeNumber()
{
    return _homeNumber;
}
public void setHomeNumber(PhoneNumber value)
{
    _homeNumber = value;
}

Какой метод вы предпочитаете? На мой взгляд, вариант 1 лучше, потому что вы знаете, что состояние объекта не может быть изменено. Я считаю, что это называется неизменность и это то, что должно быть желаемым? С другой стороны, он может быстро выйти из-под контроля и некрасиво, если у вас есть более чем несколько параметров.

Я знаю, что некоторые языки, такие как C# имеют полезные свойства, которые бы, наверное, выбрал вариант 1 более привлекательным, например, именованные и необязательные параметры, однако этот вопрос было предложено при работе с Java-кодом.

Обновление: Спасибо за все ваши предложения. Я буду комментировать каждый ответ по отдельности, но некоторые ответы предложили использовать метод фабрики вместо того, конструктор сделает всю работу. На самом деле это шаблон, который я использовал, поскольку она стандартная на работе, но я никогда не видел ее преимуществами по сравнению с использованием конструктора для выполнения работы. Это больше как код выглядел так:

private string firstname;
private string surname;
private Address homeAddress;
private PhoneNumber homeNumber;

private Person()
{
}

public Person factoryCreate(string firstname, string surname, Address homeAddress, 
                            PhoneNumber homeNumber)
{
    Person person = new Person();
    person.setFirstname(firstname);
    person.setSurname(surname);
    person.setHomeAddress(homeAddress);
    person.setHomeNumber(homeNumber);
    return person;
}

public string getFirstname()
{
    return firstname;
}
public void setFirstname(String value)
{
    firstname = value;
}

public string getSurname()
{
    return surname;
}
public void setSurname(String value)
{
    surname = value;
}

public Address getAddress()
{
    return address;
}
public void setAddress(Address value)
{
    address = value;
}

public PhoneNumber getHomeNumber()
{
    return _homeNumber;
}
public void setHomeNumber(PhoneNumber value)
{
    _homeNumber = value;
}

Из дискуссии о том, конструкторы сделать небольшую работу, и с помощью строителей, я могу понять, почему имея фабричный метод является хорошим. Мое понимание методов фабрики было то, что они были использованы для создания класса дается несколько вариантов. Например, если у вас есть работник класс и это уже классифицируется по FullTimeEmployee и PartTimeEmployee, вы бы фабрика() метод на сотрудника , чтобы справиться с созданием более конкретный класс.



5722
7
задан 15 июля 2011 в 05:07 Источник Поделиться
Комментарии
6 ответов

При строительстве объектов, имеющих конструктор, который делает очень мало, идеально подходит. Это становится особенно актуально, когда вы тестируете свои объекты с помощью модульных тестов.

Как и другие предложения, я бы оставил собственно строительство объекта, застройщика или метод фабрики. Я хотел бы подчеркнуть, что вы должны включать только параметры, которые требуются для его правильного объекта, и, как правило, требуется не более 7 (плюс-минус 2) параметров. Если у вас есть больше параметров, чем тот, ваш класс, возможно, пытается сделать слишком много.

Однако, такие вещи, как идентификатор, который относится к полю базы данных (или другой механизм хранения) лучше будет установить путем сопоставления данных, хранилища и т. д. что вы используете.

В мой родной язык программирования, это будет выглядеть примерно так:

class Person
{
private $_id; // optional (not necessary for a Person... set once stored)
private $_name; // required
private $_address; // optional

/**
* @param $name - In this example, I'm just going to pretend like this is required.
* It probably doesn't make sense for there to be an instance of a
* Person without a name.
* @return Person
*/
public static function factory( $name )
{
$Person = new Person();
$Person->setName($name);

return $Person;
}

public function setId($id)
{
$this->_id = $id;
}

public function getId()
{
return $id;
}

public function setName($name)
{
$this->_name = $name;
}

public function getName()
{
return $this->_name;
}

public function setAddress($address)
{
$this->_address = $address;
}

public function getAddress()
{
return $this->_address;
}
}

При создании человека:

$PersonRepository = new PersonRepository();
$Person = Person::factory('Sarah');
$PersonRepository->save($Person); // This generates an ID for $Person before saving

При извлечении человека:

$PersonRepository = new PersonRepository();
$Person = $PersonRepository->getById($id);

и репозитории в этом случае будет отвечать за то, что делаешь что-то вроде...

$Person = new Person();
$Person->setId($storageResult['id']);
$Person->setName($storageResult['name']);
$Person->setAddress($storageResult['address']);
return $Person;

3
ответ дан 15 июля 2011 в 09:07 Источник Поделиться

Это зависит от того, является ли элементы данных, требуемые для объекта должны быть четко определены или если они совершенно необязательны.

Мое личное предпочтение для конструктора иметь параметры для всех необходимых элементов данных и использовать набор методов для всего остального. Я также заявляю по умолчанию (без параметров) конструктор должен быть частным. Таким образом, компилятор гарантирует, что никто не будет создавать недоопределенных объектов.

Если требуется firstName и lastName, но адрес и номер телефона не являются обязательными, я бы сделал следующее:

private string _firstname;
private string _surname;
private Address _homeAddress;
private PhoneNumber _homeNumber;

private Person()
{
// Ensure unitialized Person cannot be created
}

public Person(string firstname, string surname)
{
_firstname = firstname;
_surname = surname;
}

// getters and setters omitted for brevity

Недостатком использования шаблона Builder как рекомендовано в других ответов заключается в том, что проверка полноты отложено до времени выполнения. Если у вас есть код, которые очень редко исполняются и изменить человека так, что требуется больше данных, и тогда вы могли бы поставить код, который будет не в поле. С моим подходом, вы будете знать о проблеме в следующий раз, когда вы пытаетесь скомпилировать ваш код.

10
ответ дан 15 июля 2011 в 08:07 Источник Поделиться

Я также рекомендую шаблон Строитель, однако я предпочитаю делать это таким образом:

public class Person {
private int id;
private String firstname;
private String surname;
private Address homeAddress;
// etc.

private Person() {// IMPORTANT, private constructor
}

public static class Builder {
private Person person;

public Builder(int id) {
if (id == 0) {
//fuck it
}
person = new Person();
}

public Builder setFirstname(String firstName) {
person.firstname = firstName;
return this;
}

public Builder setSurname(String surname) {
person.surname = surname;
return this;
}
// etc.

public Person build() {
// don't return the object if it was not created correctly... for instance:
if (person.firstname == null) {
throw new IllegalStateException("You are a fool");
}
return person;
}
}

public static void main(String... args) {
Person person = new Person.Builder(666)
.setFirstname("foo")
.setSurname("bar")
.build();
}
}

Главное отличие в отношении предыдущего ответа, что:


  • Вы не можете создать человек, если вы будете использовать построитель

  • Строитель знает, когда человек готов, иначе он не будет ничего возвращать.

2
ответ дан 15 июля 2011 в 07:07 Источник Поделиться

Ответ не обязательно должен быть язык агностик, потому что было бы глупо не использовать возможности языка для решения этого вопроса...
Так что ваш вопрос действителен в Java и прочими промежуточными язык, но более бессмысленно в некоторых языках более высокого уровня.

Я думала Скала, где вы действительно назвали и по умолчанию параметров, позволяющих иметь конструкторы с большим количеством параметров, сохраняя при этом читаемость: назовите параметры, по месту вызова, которые похожи на цепочки из наборов, но безопаснее в качестве обязательных параметров (не по умолчанию) должны присутствовать.

С другой стороны, вы также можете использовать уловки типа (так называемый фантомный типов, если я правильно понял, эти статьи я читал, но не полностью усваивается...), чтобы заставить застройщика сделать все необходимые элементы. Когда я пишу "силой", то бишь "насильственные компилятором", т. е.. ваш код должен быть правильным во время компиляции, это не просто проверяются во время выполнения. Мощный.

Я не буду решать ваши конкретные вопрос (решение работает для всех языков), ответы я вижу гораздо лучше, чем я мог бы сделать, но я думал, я должен упомянуть интересные альтернативы на ваш вопрос.

2
ответ дан 16 июля 2011 в 09:07 Источник Поделиться

Начиная с неизменяемыми классами обычно хорошая идея. (по данным эффективная Java). Я люблю делать вещи, когда я могу.

Вы должны также проверить застройщика образец.

Как он инкапсулирует инициализации и позволяет добавить дополнительные параметры, не влияя на подпись конструкторов.

Редактировать: вот пример на основе вашего кода, это может быть нечто среднее между C# и Java, но я думаю, вы получите идею...

public class Person {
private string firstname;
private string surname;
private Address homeAddress;
private PhoneNumber homeNumber;

public Person( Builder builder ) {
super();
this.firstname = builider.firstname;
this.surname = builder.surname;
this.homeAddress = builder.homeAddress;
this.homeNumber = builder.homeNumber;
}

pubilc static class Builder {
private integer id;//required field.
private string firstname;//optional field.
private string surname;//optional field.
private Address homeAddress;// optional field.
private PhoneNumber homeNumber;// optional field.

public Builder( integer id ) {
super();
if ( id == null ) {
//deal with it.
}
this.id = id;
}
public Builder setFirstname( string firstName ) {
this.firstname = firstname;
return this;
}
public Builder setSurname ( string surname ) {
this.surname = surname;
return this;
}
public Builder setHomeAddress( Address homeAddress ) {
this.homeAddress = homeAddress;
return this;
}
public Builder setHomeNumber( PhoneNumber homeNumber ) {
this.homeNumber = homeNumber;
return this;
}
}
// Person.getXXX() goes here.

public static void main( String...args ) {

Person.Builder builder = new Person.Builder( new integer( 123 ) );
builder.setFirstname( "foo" ).setSurname( "bar" ).setHomeAddress( new HomeAddress() ).setHomeNumber( new PhoneNumber() );

// always the same
Person person = new Person( builder );
}
}

0
ответ дан 15 июля 2011 в 05:07 Источник Поделиться


  • Конструктор сделать как меньше работать, как можно хорошо. Для меня, просто назначение параметров на местных полях не работают. Что до меня, равна нулю работа - никакая логика.

  • В зависимости от языка программирования, разметка поля как Final-это хорошо, если вы не изменяя их. Моя большая причина для этого, для удобства восприятия - ее сразу видно, что окончательное поля простой бит - не может быть изменен и меньше висит потоков, чтобы сохранить в мой поток, как я прочитал остальную часть кода. Это не похоже на крупную сделку для вашего текущего класса, но я предполагаю, что ваш фрагмент кода является частью большого класса, и даже если это не так, его довольно много, то я всегда делаю.

  • Разоблачение сеттеры просто использовать их за счет застройщика, а не где-нибудь еще представляет большую сложность(см. пункт 2).

  • С помощью конструктора приносит больше детализации. Я бы не стала использовать его только для дополнительных полей - перегрузка конструктора/передача в нулевых гораздо чище для этого. В общем, я использую шаблон построителя, когда строительный процесс более трудоемкий, то просто установить некоторые поля.

  • Слишком много параметров-это код запах, но 4 параметров, кажется, в порядке. Особенно, если они на самом деле кажется, что они принадлежат к этому классу, и они имеют различные типы среди них(не все струны, например).

Мой вывод: я бы просто отметьте поля окончательное и придерживаться вашего варианта 1. :)

0
ответ дан 21 января 2012 в 08:01 Источник Поделиться