2010-08-03 3 views
26

Шаблон строителя популярен для создания неизменяемых объектов, но для создания строителя есть некоторые накладные расходы на программирование. Поэтому я удивляюсь, почему бы просто не использовать объект конфигурации.Builder pattern vs. config object

Использование строитель будет выглядеть следующим образом:

Product p = Product.name("Vodka").alcohol(0.38).size(0.7).price(17.99).build(); 

Очевидно, что это очень читаемым и лаконичным, но вы должны реализовать строитель:

public class Product { 

    public final String name; 
    public final float alcohol; 
    public final float size; 
    public final float price; 

    private Product(Builder builder) { 
     this.name = builder.name; 
     this.alcohol = builder.alcohol; 
     this.size = builder.size; 
     this.price = builder.price; 
    } 

    public static class Builder { 

     private String name; 
     private float alcohol; 
     private float size; 
     private float price; 

     // mandatory 
     public static Builder name(String name) { 
      Builder b = new Builder(); 
      b.name = name; 
      return b; 
     } 

     public Builder alcohol(float alcohol) { 
      this.alcohol = alcohol; 
      return.this; 
     } 

     public Builder size(float size) { 
      this.size = size; 
      return.this; 
     } 

     public Builder price(float price) { 
      this.price = price; 
      return.this; 
     } 

     public Product build() { 
      return new Product(this); 
     } 

    } 

} 

Моя идея заключается в том , чтобы уменьшить код с помощью простого объекта конфигурации следующим образом:

class ProductConfig { 

     public String name; 
     public float alcohol; 
     public float size; 
     public float price; 

     // name is still mandatory 
     public ProductConfig(String name) { 
      this.name = name; 
     } 

} 

public class Product { 

    public final String name; 
    public final float alcohol; 
    public final float size; 
    public final float price; 

    public Product(ProductConfig config) { 
     this.name = config.name; 
     this.alcohol = config.alcohol; 
     this.size = config.size; 
     this.price = config.price; 
    } 

} 

Использование:

ProductConfig config = new ProductConfig("Vodka"); 
config.alcohol = 0.38; 
config.size = 0.7; 
config.price = 17.99; 
Product p = new Product(config); 

Такое использование необходимо еще несколько строк, но также очень удобным для чтения, но реализация гораздо проще и, возможно, легче понять, для кого-то, кто не знаком с моделью строитель. Кстати: есть ли название для этого шаблона?

Есть ли недостаток в настройке конфигурации, который я забыл?

+0

В 'Builder' ваши сеттеры должны« вернуть это », потому что шаблон работает. – rsp

+0

Спасибо! Я должен был проверить свой код ... – deamon

+0

С помощью подхода к объекту config вы также можете сделать вещи безопасными, используя фантомные типы. То есть, компилятор позволит вам передать экземпляр config в исходный конструктор только тогда, когда будут установлены все необходимые поля. См. Http://michid.wordpress.com/2008/08/13/type-safe-builder-pattern-in-java/ – michid

ответ

16

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

Эта развязка означает, что ваш код более удобен в обслуживании и проще в тестировании.

+2

В примере, как показано, я думаю, что все еще существует связь. Вызывающий должен знать, чтобы ссылаться на все эти цепные методы, если он пропустит один, то Продукт неправильно инициализирован. Изменения в продукте требуют изменений в построителе, требуют изменений в клиенте - звуки, связанные со мной. – djna

+1

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

+0

Это может быть единственной наиболее обоснованной причиной использования строителя, но на практике каждый делает это не в основном по этой причине, просто из-за «неизменности», забывая, что строитель изменчив и для «удобочитаемости» что-то очень субъективное, t оправдывают сложность. – danidacar

2

IMO, шаблон строитель гораздо roboust, если у вас есть такие вещи, как проверка и т.д.

Узор строитель в вашем случае может быть изменен, чтобы сделать следующее:

Product p = new ProductBuilder("pName").alcohol(0.38).size(0.7).price(17.99).build(); 

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

+0

Но подтверждение можно было бы также выполнить в конструкторе 'Product'. – deamon

+0

@deamon Согласен, Builder намного более естественный IMO и упрощает API. например сравните p = new ProductBuilder («name»). price() ... от создания свойств объекта назначения конфигурации и т. д. – naikus

-1

Вы не должны использовать общедоступное поле, но защищено или закрыто. Для доступа вам следует использовать геттеры и сеттер, чтобы сохранить инкапсуляцию.

+0

Я использовал только общедоступные поля, чтобы мой пример был коротким, но в любом случае спасибо. – deamon

+3

фактически, не всегда. Если «ProductConfig» не является частью общедоступного API, тогда это может быть так просто, как показано на рисунке. Даже Дж. Блох в «Эффективной Java 2nd Edition» говорит, что его нормальный способ иметь такие объекты значений без какой-либо логики, в которых геттеры/сеттеры будут добавлять только код с плагинами (пункт 14). – Roman

+0

Его чистый класс ценности. Поскольку валидация происходит в конструкторе реального класса, и объект конфигурации никогда не должен делиться с другими потоками, он выглядит нормально для меня. Конечно, вы теряете возможность позже ввести дополнительную проверку. В дополнение к моему тезку roman: шаблон Builder - pg 11 в Effective Java SE (пункт 2). – atamanroman

3

Какую проблему вы пытаетесь решить с помощью своего шаблона? Шаблон построителя используется для объектов со многими (необязательными) параметрами, чтобы предотвратить тонны разных конструкторов или очень длинные. Он также сохраняет ваш объект в согласованном состоянии (по сравнению с javabean pattern) во время строительства.

Разница между конструктором и «конфигурационным объектом» (похоже, что это хорошее имя) заключается в том, что вам все равно нужно создать объект с теми же параметрами с помощью конструктора или getter/setter. Это а) не решает проблему конструктора или б) сохраняет объект конфигурации в несогласованном состоянии. Несогласованные состояния объекта config действительно не повредит его, но вы можете передать незавершенный объект конфигурации в качестве параметра. [Ссылка Michids на типы фантомов, похоже, решает эту проблему, но это снова убивает читаемость (kinda sucks).] Thats большое преимущество шаблона строителя: вы можете проверить свои параметры перед тем, как создать объект и, вы можете вернуть любой подтип (действует как фабрика).

Конфигурационные объекты действительны для наборов параметров, которые являются обязательными. Я видел этот шаблон много раз в .NET или Java раньше.

+0

Я хочу иметь неизменные объекты, и я бы хотел избежать конструктора со многими параметрами или многими конструкторами. Если я выполняю проверку в конструкторе фактического объекта, объект не будет создан с недопустимым состоянием. Где преимущество выполнения валидации в строителе? – deamon

+1

Он чувствует себя более сплоченным. Вместо проверки объекта config в фактическом конструкторе вы можете оставаться в своем классе строителя и делать все связанные с этим объекты. Также не забывайте, что строитель - это передовая фабрика (которая со временем доказала). Возможность возврата подтипов или интерфейсов стоит дополнительных строк кода. Но я согласен, что объекты конфигурации могут быть подходящими иногда. – atamanroman

2

Считаете ли вы использование builder-builder?

Я думаю, что строитель (с префиксами типа «С») читает более натружно/плавно.

5

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

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

Вместо этого:

ProductConfig config = new ProductConfig("Vodka"); 
config.alcohol = 0.38; 
config.size = 0.7; 
config.price = 17.99; 
Product p = new Product(config); 

Вы можете сделать:

ProductFactory.create() 
    .drink("Vodka") 
    .whereAlcohoolLevelIs(0.38) 
    .inABottleSized(0.7) 
    .pricedAt(17.99) 
    .build(); 

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

Некоторые отличные коллекции Java, такие как коллекции Google, делают как очень либеральное, так и очень хорошее использование «Свободные интерфейсы». Я бы выбрал их в любой день над вашим «более простые в использовании/менее символы» подход:)

0

Главный недостаток заключается в том, что это не в книге Джошуа, поэтому беспилотники не могут обернуть вокруг себя головы ,

Вы используете простой объект значения для хранения нескольких аргументов, которые нужны функции (/ method/constructor), нет ничего плохого в этом, это было сделано целую вечность. Пока мы не называем необязательные параметры, нам придется разрабатывать обходные пути, подобные этому, - это позор, а не какое-то чертовски блестящее изобретение богов на Солнце.

Настоящая разница заключается в том, что вы открываете поля непосредственно. У Джошуа никогда не было публичного изменчивого поля, но он пишет API, который будет использоваться миллионами людей, большинство из которых являются дебилами, и API должны быть безопасными для развития на десятилетия вперед, и они могут выделять много человеко-месяцев только для дизайн простого класса

Кто мы такие, чтобы имитировать?

+0

Его отлично видно, чтобы выставлять поля в объектах ценности. Если вы что-то читаете (эффективная java, этот поток), тогда прочитайте все это или нет. Не раз говорили, что объекты ценности в качестве параметров иногда прекрасны. Было сказано, почему фабрики и заводы также превосходят в других случаях. Этот объект конфигурации имеет совершенно другое приложение, чем шаблон построителя. – atamanroman

+0

Лучший ответ когда-либо, java drones :) – danidacar

1

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

Что мне также нравится с геттерами/сеттерами, так это то, что вы четко видите, что вы делаете: получите или установите. Я чувствую себя со строителем, я теряю немного интуитивной ясности здесь.

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

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

Хотя я вижу цель вашего объекта конфигурации, я также думаю, что это еще больше накладных расходов, чем строитель, и для чего? Что не так с сеттерами?

Может быть, нам нужно придумать спецификаторе: примера, скажем, у вас есть

public Class FooBar() { 
    private String foo; 

    public void setFoo(String bar) { 
     this.foo = bar; 
    } 

    public String getFoo() { 
     return this.foo; 
    } 
} 

public static void main(String []args) { 

FooBar fuBar = new FooBar(); 
String myBar; 

with fuBar { 
    setFoo("bar"); 
    myBar = getFoo(); 
} 
} 

А я не знаю ... Я думаю, что это может привести к еще более быстрому написание кода без всех внутренних хлопот класса. Есть ли у кого-нибудь связь с гуру Oracle Java?

Это не выглядит так же чисто, как использование объекта с помощью строителя, но вы сохраняете время построения строителя. И вы все еще можете использовать этот класс в качестве обычного pojo/bean, который может использоваться в фреймах ...

Вы, ребята, действительно хотели бы эту статью или думаете, что это скорее сосать? Cheers

+0

Поскольку вы спросили, я не думаю, что ваше предложение по модификации языка Java является хорошим. Хотя я понимаю, что это установленная конструкция на других языках, таких как Visual Basic, я думаю, что использование плавного интерфейса/метода цепочки предлагает большую гибкость, не требуя никаких изменений в самом языке. – iX3

1

Шаблон конфигурации и шаблон строителя функционально эквивалентны. Они оба решают одни и те же проблемы -

  • Устранение необходимости в нескольких подписей конструктора

  • Разрешить поля быть установлены только во время строительства

  • позволяют потребителям только заданные значения они заботятся о и иметь логические значения по умолчанию для других значений

Все, что вы хотите сделать в одном из этих узоров, вы можете сделать в другом, например, только для разрешения состояния с помощью методов, которые выполняют проверку и настройку состояния с инкапсулированной логикой. Единственное реальное отличие заключается в том, что вам нравится создавать объекты с ключевым словом new или если вам нравится называть метод .build().