Nima uchun bunday qurilma uni quruvchi bilan birlashtiriladi?

I've recently deleted a answer of mine on Code Review, that started like this:

  maxsus shaxs (PersonBuilder builder) {
 
-ni tanlang      

To'xtating. Qizil bayroq. PersonBuilder Personni yaratadi; Bir kishi haqida biladi. Shaxs klassi PersonBuilder haqida hech narsa bilmasligi kerak - bu o'zgarmas turi. Siz bu erda aylana birlashma yaratdingiz, bu erda A Aga bog'liq bo'lgan Bga bog'liq.

     

Shaxs faqat o'z parametrlarini qo'llashi kerak;

I was slapped with a downvote, and told that (quoting) Red flag, why? The implementation here has the same shape that which Joshua Bloch's demonstrated in his "Effective Java" book(item #2).

Shunday qilib, Java'da Builder Pattern ni amalga oshirishning yagona yo'li Builder (bu narsa, bu savolga tegishli emas) va keyin mahsulotni (qurilgan ob'ekt sinf) ishlab chiqaruvchiga bog'liqlik , shunga o'xshash:

  maxsus StreetMap (Builder builder) {
    // kerakli parametrlar
    origin = builder.origin;
    destination = builder.destination;

    // Majburiy parametrlar
    waterColor = builder.waterColor;
    landColor = builder.landColor;
    highTrafficColor = builder.highTrafficColor;
    mediumTrafficColor = builder.mediumTrafficColor;
    lowTrafficColor = builder.lowTrafficColor;
}
 
-ni tanlang      
https://en.wikipedia.org/wiki/Builder_pattern #Java_example

yordamida amalga oshiriladi

Xuddi shu Oluşturucu naqshde uchun bir xil Vikipediya sahifasi, C# uchun juda vahshiy (va ancha moslashuvchan) dastur mavjud:

 //Ishlab chiqaruvchi tomonidan yaratilgan mahsulotni ifodalaydi
jamoat sinflari
{
    ommaviy avtomobil ()
    {
    }

    jamoat int Wheels {get; to'siq; }

    ochiq qatorli rang {get; to'siq; }
}
 
-ni tanlang

Ko'rib turganingizdek, mahsulot bu erda Builder class haqida hech narsa bilmaydi va barcha uchun u to'g'ridan-to'g'ri konstruktiv chaqiruv, mavhum bir zavod, ... yoki ishlab chiqaruvchi - buni tushunganimga qaraganda, hech qachon yaratuvchilik naqshining mahsuloti yaratgan narsalar haqida hech narsa bilish kerak emas.

Menga argumentlar (shubhasiz, Bloch kitobida ochiqcha himoyalangan) xizmat qilgandim, bunga asosan, konstruktorga o'nlab ixtiyoriy argumentlar bilan shaffof bo'lgan turni qayta ishlash uchun quruvchi model ishlatilishi mumkin edi. degan fikrga yopishqoq o'rniga men bu saytda biroz tadqiqot qilar edim va shubhali deb bilganimni bilar edim, ushbu dalillar suvni ushlab turmaydi .

Xo'sh, bu qanday shart? Nima uchun birinchi navbatda bo'lmasligi kerak bo'lgan muammoga nima uchun muhandislik echimlari ni keltiring? Agar Joshua Blochni bir necha daqiqadan so'ng tortib olsak, biz ikkita aniq turni birlashtirish va uni eng yaxshi amaliyot deb atash uchun bitta yaxshi, asosli sabab topa olamizmi?

Menga yukni kuplab dasturlashtirish ning barcha reekslari.

21
"Juda ko'p konstruktiv argumentlar" argumenti meni hayron qoldirmadi. Lekin bu ikkala quruvchi misollaridan ham kamroq taassurot qoldirdim. Ehtimol, uning misoli oddiy bo'lmagan xatti-harakatlarni ko'rsatish uchun juda oddiy bo'lgani uchun, lekin Java misolida ravon interfeys, kabi o'qiladi va C# misoli xususiyatlarni amalga oshirishning aylanish usuli hisoblanadi. Qaysi misolda parametrlarni tekshirishning har qanday shakli yo'q; bir konstruktor hech bo'lmaganda taqdim qilingan argumentlarning turini va sonini tasdiqlaydi, ya'ni ko'p argumentlarga ega konstruktor g'olib bo'ladi.
qo'shib qo'ydi muallif sgwill, manba
Birlashma deyarli ikkinchi darajali ahamiyatga ega.
qo'shib qo'ydi muallif sgwill, manba
@PhilipKendall U rant kabi o'qiyapti, ha, lekin uning asosiy mavzusi haqiqiy mavzu masalasi. Ehtimol, foydani ajratish mumkinmi?
qo'shib qo'ydi muallif Mike McAllister, manba
@PhilipKendall balki bir oz. Lekin men har bir Java yaratuvchisi nima uchun bu qat'iy aloqani egallashini tushunishdan juda mamnunman.
qo'shib qo'ydi muallif Mathieu Guindon, manba
Va bu "savol" odatiy hol bo'lib qolmoqda ...
qo'shib qo'ydi muallif user136413, manba
@PhilipKendall Menga qiziqish uyg'otadi.
qo'shib qo'ydi muallif Rajendra Rathore, manba

5 javoblar

Men sizning qizil bayroq ekanligingizni tasdiqlayman. Men sizning kontragentingizning vakili bilan kelishmovchilik qilmayman, Builder modelini namoyish etishning yagona yo'li bor.

To me there's one question: Is the Builder a necessary part of the type's API? Here, is the PersonBuilder a necessary part of the Person API?

Ishonchli, o'zgartirilmagan va/yoki mahkamlangan holda yashovchan bo'lgan shaxs klassi (ishlab chiqaruvchining ichki yoki qo'shni bo'lganligidan qat'i nazar) ta'minlaydigan Builder yordamida yaratiladigan mutlaqo bo'ladi. Shunday qilib, Shaxs o'zining barcha sohalarini shaxsiy yoki paketli-maxfiy va yakuniy saqlashi mumkin, shuningdek, agar u ishlayotgan bo'lsa, sinfni o'zgartirish uchun ochiq qoldirishi mumkin. (O'zgartirish uchun yopiq oxirigacha bo'lishi mumkin va kengaytma uchun ochiq, lekin hozir bu muhim emas va o'zgaruvchan ma'lumotlar obyektlari uchun ayniqsa ziddiyatli.)

Agar shaxs, albatta, taqdim etilgan PersonBuilder orqali paketli darajadagi API loyihasining bir qismi sifatida yaratilgan bo'lsa, unda dumaloq birlashma juda yaxshi va bu erda qizil bayroq kafolatlanmaydi. Ayniqsa, siz buni API ning noyob fikri yoki tanlovi emas, balki noto'g'ri javob deb bilgansiz, shuning uchun yomon javobga duch kelishingiz mumkin. Men sizni pastga tashlamagan bo'lardim, lekin men buni boshqasi uchun ayblamayman, qolgan qismini Ko'proq ko'rib chiqish yordam markazi va meta . Tepaliklar yuz beradi; bu "slap" emas.

Albatta, agar Person obyektini yaratish uchun ochiq bo'lgan ko'p yo'llarni tark etmoqchi bo'lsangiz, PersonBuilder Shaxs sinfi uchun iste'molchi yoki yordamchi dasturi bo'lishi mumkin. Shaxs to'g'ridan-to'g'ri bog'liq bo'lmasligi kerak. Bu tanlov yanada moslashuvchan ko'rinadi-kimda ob'ekt yaratish variantlarini istamaydi? Ammo, kafolatni ushlab turish uchun (masalan, o'zgarmaslik yoki serializablelik kabi) to'satdan Shaxs, turli xil jamoat yaratish texnikasini, masalan, juda uzoq muddatli konstruktor . Agar builder konstruktorni ixtiyoriy joylar yoki modifikatsiyaga ochiq bo'lgan konstruktor bilan ifodalash yoki o'zgartirishi kerak bo'lsa, unda sinfning uzoq konstruktori yaxshi saqlangan dastur batafsil bo'lishi mumkin. (Shuningdek, rasmiy va kerakli qurilish muhandisi sizning o'zingizning qurilish yordam dasturini yozib olishingizga to'sqinlik qilmaydi, chunki sizning qurilish xizmatidan foydalanish muhiti yaratuvchisini yuqoridagi asl savolimdagidek API sifatida ishlatishi mumkin).


p.s .: Siz qayd qilgan kodni ko'rib chiqish namunasi o'zgarmas shaxsga ega ekanligini unutmang, lekin Vikipediyadagi kontr-misolda o'zgaruvchan va sozlash bilan o'zgaruvchan Avtomobil ro'yxati keltirilgan. Tilni va indivantitlarni ular orasidagi izchil ushlab tursangiz, avtomobildan olib tashlangan zarur mashinani ko'rish osonroq bo'lishi mumkin.

22
qo'shib qo'ydi
@ Mat'sMug StringBuilder bu o'zgaruvchan mag'lubiyatning ishlash optimizatsiyasidir, u String turini ishlab chiqaruvchi emas (eng kamida, mag'lubiyatga qurish uchun hech narsa yo'q, chunki amaldagi murakkabliklarni e'tiborsiz qoldiruvchi, mag'lubiyat faqat "bir qiymat"). Hech narsa XXXBuilder deb ataladigan bo'lsa, u XXX uchun ishlab chiqaruvchi namunasini amalga oshirilishini anglatmaydi. StringBuilder.ToString() sizga StringBuilder tomonidan kiritilgan string "joylashgan" ni beradi. NET, ikkita bir xil bo'ladi, bundan tashqari string o'zgaruvchan emas, bu faqat ish vaqti hack).
qo'shib qo'ydi muallif Luaan, manba
@chrylis. NETda StringBuilder argumentini olgan string asoschisi yo'q. Buning ortidan matning sharhida kontentga kirishingiz kerak: D
qo'shib qo'ydi muallif Luaan, manba
Haqiqiy hayotda bir necha Person ning boshqa Person s tuzishi mumkinligiga aminman. Bu qurilishga o'xshashmi?
qo'shib qo'ydi muallif Elysian Fields, manba
Adolatli. Hali ham String (StringBuilder) konstruktorini sotib olmoqchi emasman, biroq, bu "printsipga" mos keladi. Men konstruktorni haddan tashqari yuklarni ko'rganimda shunchalik xafa bo'ldim. String kabi 42 konstruktor parametrlari mavjud emas ...
qo'shib qo'ydi muallif Mathieu Guindon, manba
Shunga qaramasdan, juda ko'p konstruktiv argumentli turi mavjud bo'lgan dizayn masalasi (SRPni buzishning hidlari) bo'lganligi, quruvchi modelning gilam ostida tezlik bilan siljishi degan fikrni silkitmaydi.
qo'shib qo'ydi muallif Mathieu Guindon, manba
Men konstruktorni dastur detali sifatida muolaja qilish haqidagi fikringizni ko'rib chiqaman. Java iTunes "tonna" deb nom olgan bir tonna qoldirib, " Effektiv Java ga o'xshab ko'rinmaydi» (bu kitobni o'qimaganman/o'qimaganman) bu "aql-idrokidan qat'iy nazar" amalga oshiriladi. Vikipediyadagi misollarni taqqoslash uchun yomon deb hisoblayman. Lekin, bu Vikipediya .. va FWIW Men aslida pastga tushirishni o'ylamayman; o'chirilgan javobi allaqachon ijobiy natija bilan o'tiribdi (va men nihoyat [nishon: tengdoshlarning bosimi] uchun imkoniyatni topaman.
qo'shib qo'ydi muallif Mathieu Guindon, manba
@ Mat'sMug ichida to'plami yoki String StringBuilderni ishlatadi, StringBuilder Stringni ishlatadi yoki ular bir xil yuqori darajadagi sinfda joylashgan. tashqarida to'plami, u muhim emas; ular bir xil API sirtining ajralmas qismlari. Va shunga o'xshash sharhlar uchun, bu Josh Blokning API loyihalash nutqi ga qarang uning maslahati va ( Effektiv Java 2-nashrida kabi) u Java kutubxonalarida yomon API loyihalash tanlovini tanqid qiladi. Link 36:41 ga boradi, lekin butun nutqni tomosha qilish kerak.
qo'shib qo'ydi muallif JerzyGora, manba
@ Mat'sMug Yuqoridagi xabarim buni sinfi ko'plab konstruktiv argumentlarga kerak ga mos ravishda oladi. Agar biz o'zboshimchalik bilan ishbilarmonlik mantiqiy qismi haqida gapiradigan bo'lsak, men uni dizayner hidiga aylantirmoqchiman, ammo ma'lumot obyekti uchun bunday turdagi o'n yoki yigirmata bevosita atributga ega bo'lish masalasi emas. Ob'ektga nisbatan SRP-ning buzilganligi " Bir-biriga qattiq yozilgan yozuvni masalan, logi .
qo'shib qo'ydi muallif JerzyGora, manba
@Luaan Java API-lari bir xil bo'lgani bois, siz nimani afzal ko'rganingiz haqida aniq emas.
qo'shib qo'ydi muallif Marc-André Lafortune, manba
@Luaan Odd. To'g'ri ishlatilganini hecham ko'rmadim va u mavjudligini bilmasdim; toString() umumiydir.
qo'shib qo'ydi muallif Marc-André Lafortune, manba
Java'da siz tasvirlab bergan holda, odatda, Person.Builder va ehtimol Person da maxsus ijobiy bo'lishi uchun odatiy holga kelishi mumkin.
qo'shib qo'ydi muallif Marc-André Lafortune, manba

Men "hokimiyatga murojaat qilish" deb atalgan munozarada qanday foydalanishi mumkinligini bilaman. Argumentlar o'zlarining IMO-lariga qarashlari kerak va bunday hurmatli insonning tavsiyasiga ishora qilish noto'g'ri bo'lmasa-da, bu haqiqatan ham to'liq argument deb hisoblanmaydi, chunki Quyosh Er atrofida sayyorani biladi, chunki Aristotel .

Buni aytgandan so'ng, sizning argümanlarınızın bir xil turini deb o'ylayman. Biz hech qachon ikkita aniq turni birlashtirmasligimiz kerak va uni yaxshi amaliyot deb atashimiz kerak ... Chunki kimdir shunday deb aytgandi?

Birlashuvning mantiqiy ekanligi haqidagi dalillar uchun, u yaratadigan muayyan muammolar bo'lishi kerak. Agar bu yondashuv ushbu masalalarga bo'ysunmasa, mantiqiy ravishda bunday aloqa shakli muammoli ekanligi haqida bahslasholmaydi. Shunday qilib, sizning fikringizni bu erga qo'yishni istasangiz, menimcha, ushbu yondashuv ushbu mavzularga qanday ta'sir qilishini va/yoki ishlab chiqaruvchining dizayni qanday takomillashtirishini ko'rsatishi kerak.

Ehtimol, men birlashtirilgan yondoshuvning muammolarni qanday yaratishini ko'rish uchun kurashmoqdaman. Sinflar mutlaqo birlashtirilgan, albatta, lekin builder faqat sinf misollarini yaratish uchun mavjud. Bunga qarashning yana bir usuli - bu konstruktorning kengayishi.

7
qo'shib qo'ydi
@ Mat'sMug Ma'lumotlarni uzluksiz ob'ektlarga surish uchun juda foydali bo'lishi mumkin. Ushbu turdagi narsalar, aslida, OO emas, balki xususiyatlarga ega bo'lgan sumka bo'lishi mumkin. Bunday muammolarning barchasi, PITA kabi, yaxshi amaliyotlarga rioya qiladimi yoki yo'qmi, ulardan foydalanishga yordam beradi.
qo'shib qo'ydi muallif JimmyJames, manba
@ Mat'sMug Tushunish uchun, men bu ikki jihatdan kuchli tuyg'uga ega emasman. Ishlab chiqaruvchining namunasidan foydalanishga moyil emasman, chunki men ko'plab davlat yozuvlari mavjud bo'lgan sinflarni yaratmayapman. Umuman olganda, men sizni boshqa joylarga o'xshatgan sabablarga ko'ra bunday sinfga o'xshatib qo'yaman. Men aytmoqchimanki, bu yondashuv qanday qilib muammoga olib kelishi mumkinligini ko'rsatsangiz, Xudo tosh tushganmi yoki tosh platada Musoga bu quruvchi naqshini berganmi, muhim emas. Siz yutdingiz'. Boshqa tarafdan, agar qila olmasangiz ...
qo'shib qo'ydi muallif JimmyJames, manba
O'z kodlarim bazasida yaratilgan quruvchi modellardan biri qonuniy foydalanish - VBIDE API-ni mocking qilish; asosan siz kod modulining magistral tarkibini ta'minlaysiz va yaratuvchisiz sizga Windows kodi, faol kod bo'limi, loyiha va siz taqdim etgan mag'lubiyatni o'z ichiga olgan modul bilan topgan komponentni taqdim qiluvchi VBE Hech bo'lmasa, men qanday qilib testlarning 80% ni Rubberduck , hech bo'lmasa, har gal ko'zlarimga biqin qilmasdan, ularga qarayman.
qo'shib qo'ydi muallif Mathieu Guindon, manba
Shunday qilib ... yuqori kavramalar, pastki birlashish => baxtli oxiri bormi? hmm ... "Konstruktorni kengaytirmoqchi" haqida gapiradigan narsani ko'rmoqchiman, lekin boshqa bir misolni keltirmoqchi bo'lsak, String kodlashni amalga oshiruvchi StringBuilder parametrini (u StringBuilder bir builder deb nomlangan bo'lsa-da, lekin bu boshqa hikoya).
qo'shib qo'ydi muallif Mathieu Guindon, manba

Nima uchun bunday ishlab chiqaruvchilar bilan bog'lanishiga javob berish uchun, nima uchun kimdir birinchi navbatda quruvchi foydalanishi mumkinligini tushunish kerak. Ayniqsa: Bloch ko'pgina konstruktiv parametrlarga ega bo'lganingizda, ishlab chiqaruvchidan foydalanishni tavsiya qiladi. Bu quruvchidan foydalanishning yagona sababi emas, lekin men buni keng tarqalgan deb hisoblayman. Muxtasar qilib aytganda, quruvchi ushbu konstruktor parametrlari uchun o'rnini oladi va ko'pincha quruvchi u qurilayotgan bir sinfda e'lon qilinadi. Shunday qilib, yopuvchi sinf allaqachon ishlab chiqaruvchining bilimiga ega va konstruktiv argument sifatida uni almashtirish uni o'zgartirmaydi. Shu sababli, uning turi uni quruvchi bilan birlashtiriladi.

Nima uchun juda ko'p sonli parametrlarga ega bo'lish siz ishlab chiqaruvchidan foydalanish kerakligini anglatadimi? Xo'sh, juda ko'p sonli parametrlarga ega bo'lish haqiqiy dunyoda juda kam uchraydi va bitta mas'uliyat printsipini buzmaydi. Bundan tashqari, siz o'n string parametrlari bor va qaysi qaysi biri ekanligini va u null bo'lishi kerak bo'lgan beshinchi yoki oltinchi String-bo'lmasligini eslashga harakat qilayotganda so'radi. Ishlab chiqaruvchi parametrlarni boshqarishni osonlashtiradi va shuningdek, kitobni o'qib chiqishingiz kerak bo'lgan boshqa salqin narsalarni ham bajarishi mumkin.

Qachon siz uning turiga mos kelmaydigan quruvchi foydalanasiz? Odatda ob'ekt tarkibiy qismlari darhol mavjud bo'lmaganda va ushbu qismlarga ega bo'lgan narsalar siz yaratmoqchi bo'lgan turini bilishingizga hojat yo'q yoki siz tekshirmaydigan sinf uchun quruvchi qo'shmoqdasiz .

4
qo'shib qo'ydi
Oddiy, faqatgina kerak bo'lgan bir vaqtning o'zida, bu kabi MockVbeBuilder ; Bir test oddiy kod moduliga kerak bo'lishi mumkin, boshqa testda ikkita shakl va sinf moduli bo'lishi mumkin - IMO bu GoF ning yaratuvchisi namunasi uchun. Ya'ni, men uni boshqa bir sinf uchun aqldan ozdiruvchi bilan foydalanishni boshlashim mumkin ... lekin bu shunchaki mutlaqo to'g'ri bo'lmaydi.
qo'shib qo'ydi muallif Mathieu Guindon, manba
@ Mat 's Mugs Siz taqdim etgan sinf, builder dizayn naqshini (Gamma va boshq. Ikkalasi ham narsalarni qurishadi, lekin ular bir xil emas. Bundan tashqari, siz hech qachon qurilishga ehtiyoj sezmaysiz, boshqa narsalarni osonlashtiradi.
qo'shib qo'ydi muallif Marvin Oßwald, manba

yaratilish naqshining mahsuloti, uni yaratgan narsalar haqida hech narsa bilish kerak emas.

The Person class doesn't know what's creating it. It only has a constructor with a parameter, so what? The name of the type of the parameter ends with ...Builder which doesn't really force anything. It's just a name after all.

The builder is a glorified1 configuration object. And a configuration object is really just grouping properties together that belong to each other. If they only belong to each other for the purpose of being passed to the constructor of a class, so be it! Both origin and destination of the StreetMap example are of type Point. Would it be possible to pass the individual coordinates of each point to the map? Sure, but the properties of a Point belong together, plus you can have all kinds of methods on them that help with their construction:

1The difference is that the builder is not just a plain data object, but allows for these chained setter calls. The Builder is mostly concerned with how to build itself.

Keling, aralashuvga buyruqlar tuzilishi qo'shamiz, chunki agar siz diqqat bilan qarasangiz, ishlab chiqaruvchi aslida buyruqlar:

  1. Boshqa bir sinfga tegishli usulni chaqiruvchi
  2. ishni qamrab oladi
  3. Ushbu operatsiyani bajarish uchun kerakli ma'lumotlarni oladi: usuli parametrlari uchun qiymatlar

Quruvchi uchun maxsus qism quyidagilardan iborat:

  1. Chiqish usuli, aslida, bir sinfning konstruktori. yaratilish naqshini deb atash yaxshiroq.
  2. Parametr qiymati builderning o'zi

Person konstruktoriga o'tish mumkin bo'lgan narsa, uni tuzishi mumkin, lekin bu majburiy emas. Oddiy eski konfiguratsiya obyekti yoki quruvchi bo'lishi mumkin.

1
qo'shib qo'ydi

Yo'q, ular butunlay noto'g'ri va siz mutlaqo haqsiz. Ushbu quruvchi modeli nafaqat ahmoqdir. Bu Konstruktorlar arolari kelib chiqqan Shaxsning ishlaridan biri emas. Quruvchi foydalanuvchilar uchun qulaylik va boshqa hech narsa emas.

0
qo'shib qo'ydi
Bunga qarshi nuqta uchun qabul qilingan javobni ko'ring, bu erda PersonBuilder aslida Person API ning muhim qismi hisoblanadi. Qolaversa, bu javob uning ishi haqida tortishmaydi.
qo'shib qo'ydi muallif Mike McAllister, manba
Ha, men +1 ni tanladim, bu shartnoma bilan bir xil kafolatlar va kafolatlar beruvchi quruvchi uchun muqobil yondashuv
qo'shib qo'ydi muallif matt freake, manba
Rahmat ... Ishonchim komilki, bu javob biroz kattaroq bo'lsa, ko'proq ovoz to'play olishiga ishonchim komil, bu tugallanmagan javobga o'xshaydi =)
qo'shib qo'ydi muallif Mathieu Guindon, manba