มันเป็นเรื่องลึกลับเล็กน้อยที่จะพูดให้น้อยที่สุดเท่าที่คุณจำได้ซึ่งอาจทำให้ฉันเกาหัวสักครู่เมื่อฉันเริ่มพบรหัสของคุณก่อนที่สงสัยว่าคุณกำลังทำอะไรอยู่ / อุปนิสัย (ณ จุดที่ฉันอาจคุ้นเคยกับมันทั้งหมด)
ฉันชอบที่คุณลดปริมาณข้อมูลในส่วนหัว โดยเฉพาะอย่างยิ่งในฐานรหัสขนาดใหญ่มากที่สามารถมีผลในทางปฏิบัติเพื่อลดการพึ่งพาเวลารวบรวมและในที่สุดก็สร้างครั้ง
ปฏิกิริยาทางเดินอาหารของฉันคือว่าถ้าคุณรู้สึกว่าจำเป็นต้องซ่อนรายละเอียดการใช้งานด้วยวิธีนี้เพื่อให้การสนับสนุนพารามิเตอร์ที่ส่งผ่านไปยังฟังก์ชั่นว่างด้วยการเชื่อมโยงภายในในไฟล์ต้นฉบับ โดยปกติแล้วคุณสามารถใช้ฟังก์ชั่นยูทิลิตี้ (หรือคลาสทั้งหมด) มีประโยชน์สำหรับการใช้คลาสเฉพาะโดยไม่ต้องเข้าถึง internals ทั้งหมดของคลาสและเพียงแค่ส่งผ่านสิ่งที่เกี่ยวข้องจากการใช้เมธอดไปยังฟังก์ชัน (หรือคอนสตรัคเตอร์) และเป็นธรรมชาติที่มีโบนัสในการลดการมีเพศสัมพันธ์ระหว่างชั้นเรียนของคุณและ "ผู้ช่วยเหลือ" นอกจากนี้ยังมีแนวโน้มที่จะสรุปสิ่งที่อาจเป็น "ผู้ช่วยเหลือ" เพิ่มเติมหากคุณพบว่าพวกเขาเริ่มให้บริการวัตถุประสงค์ทั่วไปที่ใช้กับการใช้งานมากกว่าหนึ่งชั้น
บางครั้งฉันก็ประจบประแจงเล็กน้อยเมื่อฉันเห็น "ผู้ช่วยเหลือ" จำนวนมากในรหัส มันไม่ได้เป็นความจริงเสมอไป แต่บางครั้งพวกเขาก็สามารถแสดงอาการของนักพัฒนาที่เพิ่งสลายฟังก์ชั่นโดยจำใจเพื่อกำจัดการทำซ้ำโค้ดด้วยการหยดข้อมูลขนาดใหญ่ที่ถูกส่งผ่านไปยังฟังก์ชันที่มีชื่อ / วัตถุประสงค์ที่เข้าใจยาก รหัสที่จำเป็นสำหรับการใช้งานฟังก์ชั่นอื่น ๆ เพียงเล็กน้อยคิดล่วงหน้าเล็ก ๆ น้อย ๆ บางครั้งอาจนำไปสู่ความชัดเจนมากขึ้นในแง่ของวิธีการใช้งานของชั้นเรียนถูกแบ่งออกเป็นฟังก์ชั่นเพิ่มเติมและการสนับสนุนผ่านพารามิเตอร์ที่เฉพาะเจาะจงเพื่อส่งผ่านกรณีทั้งหมดของวัตถุของคุณ ส่งเสริมแนวคิดการออกแบบ ฉันไม่แนะนำให้คุณทำอย่างนั้นแน่นอน (ฉันไม่รู้)
หากสิ่งนั้นกลายเป็นเรื่องไม่แน่นอนฉันจะพิจารณาวิธีแก้ปัญหาที่สองซึ่งเป็นสำนวนมากกว่าซึ่งเป็น pimpl (ฉันรู้ว่าคุณพูดถึงปัญหาด้วย แต่ฉันคิดว่าคุณสามารถสรุปวิธีแก้ปัญหาเพื่อหลีกเลี่ยงปัญหาเหล่านั้นด้วยความพยายามน้อยที่สุด) ที่สามารถย้ายข้อมูลจำนวนมากทั้งหมดที่คลาสของคุณต้องการนำไปใช้รวมถึงข้อมูลส่วนตัวของมันอยู่ห่างจากส่วนหัวขายส่ง ปัญหาด้านประสิทธิภาพของ pimpl สามารถลดลงได้อย่างมากด้วยตัวจัดสรรเวลาคงที่ราคาถูกสกปรก * เหมือนรายการฟรีในขณะที่รักษาความหมายของค่าโดยไม่ต้องใช้ ctor สำเนาที่ผู้ใช้กำหนดเองเต็มรูปแบบ
- สำหรับด้านประสิทธิภาพ pimpl แนะนำค่าใช้จ่ายตัวชี้อย่างน้อยที่สุด แต่ฉันคิดว่าคดีต้องร้ายแรงมากที่ต้องคำนึงถึงเรื่องจริง หากตำแหน่งเชิงพื้นที่ไม่ได้ลดลงอย่างมีนัยสำคัญผ่านตัวจัดสรรดังนั้นลูปที่วนซ้ำของคุณจะวนซ้ำกับวัตถุ (ซึ่งโดยทั่วไปควรเป็นเนื้อเดียวกันหากประสิทธิภาพนั้นเป็นเรื่องที่น่ากังวลมาก) จะยังคงมีแนวโน้มที่จะลดการพลาดแคชในทางปฏิบัติ รายการอิสระในการจัดสรร pimpl ทำให้ฟิลด์ของคลาสเป็นบล็อกหน่วยความจำที่ต่อเนื่องกันเป็นส่วนใหญ่
โดยส่วนตัวหลังจากหมดความเป็นไปได้เหล่านั้นฉันจะพิจารณาบางอย่างเช่นนี้ ฉันคิดว่ามันเป็นความคิดที่ดีถ้าทางเลือกเป็นเหมือนวิธีการส่วนตัวที่เปิดเผยกับส่วนหัวซึ่งอาจมีเพียงความลึกลับที่เป็นความลับในทางปฏิบัติ
ทางเลือก
ทางเลือกหนึ่งที่โผล่เข้ามาในหัวของฉันในตอนนี้ที่ทำให้เป้าหมายเดียวกันกับเพื่อนที่ขาดไปของคุณส่วนใหญ่เป็นเช่นนี้:
struct PredicateListData
{
int somePrivateField;
};
class PredicateList
{
PredicateListData data;
public:
bool match() const;
};
// In source file:
static bool fullMatch(const PredicateListData& p)
{
// Can access p.somePrivateField here.
}
bool PredicateList::match() const
{
return fullMatch(data);
}
ตอนนี้อาจดูเหมือนว่าจะแตกต่างกันมากและฉันก็ยังเรียกมันว่า "ผู้ช่วยเหลือ" (ในความรู้สึกเสื่อมเสียเนื่องจากเรายังคงส่งผ่านสถานะภายในทั้งหมดของคลาสไปยังฟังก์ชันไม่ว่าจะต้องการทั้งหมดหรือไม่ก็ตาม) ยกเว้นว่ามันจะไม่หลีกเลี่ยง "ช็อต" friend
ปัจจัยที่จะเผชิญหน้า โดยทั่วไปแล้วfriend
ดูน่ากลัวนิดหน่อยที่จะเห็นการขาดการตรวจสอบเพิ่มเติมบ่อยครั้งเนื่องจากมันบอกว่า internals ในชั้นเรียนของคุณสามารถเข้าถึงได้จากที่อื่น (ซึ่งมีความหมายว่า ด้วยวิธีที่คุณใช้friend
มันจะกลายเป็นข้อสงสัยหากผู้คนตระหนักถึงการปฏิบัติตั้งแต่friend
เป็นเพียงการอยู่ในไฟล์ต้นฉบับเดียวกันเพื่อช่วยในการใช้งานฟังก์ชั่นส่วนตัวของชั้นเรียน แต่สิ่งที่กล่าวมาข้างต้นนั้นประสบความสำเร็จอย่างมากในเรื่องเดียวกันอย่างน้อยก็มีข้อดีที่พิสูจน์ได้ว่ามันไม่เกี่ยวข้องกับเพื่อน ๆ shoot คลาสนี้มีเพื่อนคนอื่น ๆ จะเข้าถึงหรือกลายพันธุ์ได้ที่ไหน ") ในขณะที่รุ่นเหนือทันทีสื่อสารว่ามีวิธีไม่มีไพร่พลที่จะเข้าถึง / PredicateList
นอกกลายพันธุ์ของสิ่งที่ทำในการดำเนินงานของ
นั่นอาจจะเคลื่อนไปสู่ดินแดนดื้อดึงที่มีระดับความแตกต่างกันเล็กน้อยเนื่องจากใคร ๆ ก็สามารถรู้ได้อย่างรวดเร็วว่าคุณมีชื่อที่เหมือนกัน*Helper*
และทำให้พวกเขาทั้งหมดอยู่ในไฟล์ต้นฉบับเดียวกันซึ่งมันรวมกันเป็นส่วนหนึ่งของการนำคลาสส่วนตัว แต่ถ้าเราได้รับจู้จี้จุกจิกบางทีสไตล์ข้างต้นในทันทีจะไม่ทำให้เกิดปฏิกิริยากระตุกเข่ามากนักโดยไม่รวมfriend
คำสำคัญที่มีแนวโน้มจะดูน่ากลัวเล็กน้อย
สำหรับคำถามอื่น ๆ :
ผู้บริโภคสามารถกำหนด PredicateList_HelperFunctions คลาสของตัวเองและให้พวกเขาเข้าถึงฟิลด์ส่วนตัว ในขณะที่ฉันไม่เห็นว่านี่เป็นปัญหาใหญ่ (ถ้าคุณต้องการที่เขตข้อมูลส่วนตัวเหล่านั้นคุณสามารถทำการคัดเลือกนักแสดงได้) บางทีมันอาจกระตุ้นให้ผู้บริโภคใช้มันอย่างนั้น?
นั่นอาจเป็นไปได้ที่จะข้ามขอบเขตของ API ซึ่งไคลเอนต์สามารถกำหนดคลาสที่สองด้วยชื่อเดียวกันและเข้าใช้งาน internals ในลักษณะที่ไม่มีข้อผิดพลาดในการเชื่อมโยง จากนั้นอีกครั้งฉันส่วนใหญ่ C coder ทำงานในกราฟิกที่ความกังวลด้านความปลอดภัยในระดับนี้ "เกิดอะไรขึ้น" ต่ำมากในรายการลำดับความสำคัญดังนั้นความกังวลเช่นนี้เป็นเพียงคนที่ฉันมักจะโบกมือและเต้นรำ พยายามแสร้งทำเหมือนไม่มีอยู่จริง :-D หากคุณกำลังทำงานในโดเมนที่มีความกังวลเช่นนี้ค่อนข้างร้ายแรง แต่ฉันคิดว่านั่นเป็นสิ่งที่ควรพิจารณา
ข้อเสนอทางเลือกข้างต้นยังหลีกเลี่ยงปัญหานี้ หากคุณยังต้องการใช้งานต่อไปfriend
คุณสามารถหลีกเลี่ยงปัญหานั้นได้ด้วยการทำให้ผู้ช่วยเป็นคลาสที่ซ้อนกันแบบไพรเวต
class PredicateList
{
...
// Declare nested class.
class Helper;
// Make it a friend.
friend class Helper;
public:
...
};
// In source file:
class PredicateList::Helper
{
...
};
นี่เป็นรูปแบบการออกแบบที่รู้จักกันดีว่ามีชื่อหรือไม่
ไม่มีความรู้ของฉัน ฉันสงสัยว่าจะมีอย่างใดอย่างหนึ่งเนื่องจากเป็นการเข้าถึงข้อมูลและรูปแบบการใช้งานจริง ๆ
"ผู้ช่วยนรก"
ฉันได้รับการร้องขอให้ชี้แจงเพิ่มเติมเกี่ยวกับจุดที่ว่าฉันประจบประแจงบางครั้งเมื่อฉันเห็นการใช้งานด้วยรหัส "ตัวช่วย" มากมายและนั่นอาจขัดแย้งกับบางอย่างเล็กน้อย จากการใช้ชั้นเรียนของเพื่อนร่วมงานเพื่อค้นหา "ผู้ช่วยเหลือ" จำนวนมาก :-D และฉันไม่ได้เป็นคนเดียวในทีมที่เกาหัวของฉันพยายามที่จะคิดออกว่าผู้ช่วยเหลือเหล่านี้ควรทำอะไรกันแน่ ฉันไม่ต้องการหลุดพ้นจากความดันทุรังเช่น"คุณไม่ควรใช้ผู้ช่วย"แต่ฉันจะแนะนำเล็กน้อยว่ามันอาจช่วยคิดเกี่ยวกับวิธีการใช้สิ่งต่าง ๆ ที่ขาดหายไปเมื่อใช้งานจริง
ไม่ได้เป็นสมาชิกฟังก์ชั่นส่วนตัวของผู้ช่วยฟังก์ชั่นตามคำนิยาม?
และใช่ฉันรวมถึงวิธีการส่วนตัว ถ้าฉันเห็นชั้นเรียนที่มีอินเทอร์เฟซสาธารณะตรงไปตรงมา แต่ชอบวิธีการส่วนตัวแบบไม่มีที่สิ้นสุดซึ่งค่อนข้างชัดเจนในวัตถุประสงค์เช่นfind_impl
หรือfind_detail
หรือfind_helper
จากนั้นฉันก็ประจบประแจงในลักษณะที่คล้ายกัน
สิ่งที่ฉันแนะนำว่าเป็นอีกทางเลือกหนึ่งคือฟังก์ชั่นที่ไม่เป็นสมาชิกที่ไม่ใช่สมาชิกที่มีการเชื่อมโยงภายใน (ประกาศstatic
หรือภายในเนมสเปซที่ไม่ระบุชื่อ) เพื่อช่วยให้ชั้นเรียนของคุณมีจุดประสงค์ทั่วไป และฉันสามารถอ้างอิง Herb Sutter จาก C ++ 'มาตรฐานการเข้ารหัส' ได้ที่นี่เพราะเหตุใดจึงเป็นที่นิยมในมุมมอง SE ทั่วไป:
หลีกเลี่ยงค่าธรรมเนียมการเป็นสมาชิก: หากเป็นไปได้ควรทำฟังก์ชั่นที่ไม่ใช่สมาชิก nonfriends [... ] ฟังก์ชั่นที่ไม่ใช่สมาชิกที่ไม่เป็นเพื่อนปรับปรุงการห่อหุ้มโดยลดการพึ่งพา: ร่างกายของฟังก์ชั่นไม่สามารถขึ้นอยู่กับสมาชิกที่ไม่เปิดเผยต่อสาธารณะของชั้นเรียน (ดูหัวข้อ 11) พวกมันยังแยกชั้นหินใหญ่ออกเป็นชั้น ๆ เพื่อปลดปล่อยการทำงานที่แยกกันได้ช่วยลดการมีเพศสัมพันธ์ (ดูข้อ 33)
คุณยังสามารถเข้าใจ "ค่าธรรมเนียมสมาชิก" ที่เขาพูดถึงในระดับหนึ่งในแง่ของหลักการพื้นฐานของการ จำกัด ขอบเขตตัวแปรให้แคบลง ถ้าคุณจินตนาการว่าเป็นตัวอย่างที่ดีที่สุดเป็นวัตถุพระเจ้าที่มีรหัสทั้งหมดที่จำเป็นสำหรับโปรแกรมทั้งหมดของคุณเพื่อเรียกใช้แล้วโปรดปราน "ผู้ช่วยเหลือ" ของการจัดเรียงนี้ (ฟังก์ชั่นไม่ว่าจะเป็นฟังก์ชั่นสมาชิกหรือเพื่อน) ซึ่งสามารถเข้าถึงภายในทั้งหมด ไพร่พล) ของคลาสทำให้ตัวแปรเหล่านั้นมีปัญหาไม่น้อยไปกว่าตัวแปรทั่วโลก คุณมีปัญหาทั้งหมดในการจัดการสถานะอย่างถูกต้องและจัดการเรื่องความปลอดภัยและรักษาค่าคงที่ที่คุณจะได้รับจากตัวแปรทั่วโลกในตัวอย่างสุดขีดนี้ และแน่นอนว่าตัวอย่างจริงส่วนใหญ่ไม่ได้หวังว่าจะอยู่ใกล้กับจุดสุดยอดนี้ แต่การซ่อนข้อมูลมีประโยชน์เพียงเพราะมัน จำกัด ขอบเขตของข้อมูลที่ถูกเข้าถึง
ตอนนี้ซัทเทอร์ให้คำอธิบายที่ดีอยู่แล้วที่นี่ แต่ฉันยังจะเพิ่มเติมต่อไปว่า decoupling มีแนวโน้มที่จะส่งเสริมเช่นการปรับปรุงทางจิตวิทยา (อย่างน้อยถ้าสมองของคุณทำงานเหมือนของฉัน) ในแง่ของวิธีการออกแบบฟังก์ชั่น เมื่อคุณเริ่มออกแบบฟังก์ชั่นที่ไม่สามารถเข้าถึงทุกสิ่งในชั้นเรียนยกเว้นเฉพาะพารามิเตอร์ที่เกี่ยวข้องที่คุณส่งผ่านหรือถ้าคุณส่งตัวอย่างของคลาสเป็นพารามิเตอร์สมาชิกสาธารณะเท่านั้นก็มีแนวโน้มที่จะส่งเสริมแนวคิดการออกแบบที่โปรดปราน ฟังก์ชั่นที่มีจุดประสงค์ที่ชัดเจนกว่า decoupling และส่งเสริมการห่อหุ้มที่ดีขึ้นกว่าสิ่งที่คุณอาจถูกล่อลวงให้ออกแบบถ้าคุณเข้าถึงทุกอย่างได้
ถ้าเรากลับไปที่สุดขั้วแล้วโค้ดเบสที่เต็มไปด้วยตัวแปรทั่วโลกไม่ได้ดึงดูดนักพัฒนาให้ออกแบบฟังก์ชั่นในลักษณะที่ชัดเจนและมีจุดประสงค์ทั่วไป ยิ่งคุณเข้าถึงข้อมูลในฟังก์ชันได้เร็วเท่าไรมนุษย์ของเราจำนวนมากต้องเผชิญกับการล่อลวงเพื่อทำให้เสื่อมและลดความชัดเจนในการเข้าถึงข้อมูลพิเศษทั้งหมดที่เรามีแทนที่จะยอมรับพารามิเตอร์ที่เฉพาะเจาะจงและเกี่ยวข้องกับฟังก์ชันนั้นมากขึ้น เพื่อ จำกัด การเข้าถึงของรัฐและขยายการบังคับใช้และปรับปรุงความชัดเจนของความตั้งใจ ที่ใช้ (แม้ว่าโดยทั่วไปจะมีระดับที่น้อยกว่า) กับฟังก์ชั่นสมาชิกหรือเพื่อน