รหัส“ คุณสมบัติอิจฉา” คืออะไรและเหตุใดจึงถือว่าเป็นกลิ่นรหัส


52

นี้คำถามเกี่ยวกับ SOพูดคุยเกี่ยวกับการแก้ไขสิ่งที่คิด OP คือคุณลักษณะอิจฉารหัส อีกตัวอย่างหนึ่งที่ฉันเห็นวลีที่ดีนี้ถูกอ้างถึงในคำตอบที่ได้รับเมื่อเร็ว ๆ นี้ใน programmers.SE ถึงแม้ว่าผมจะไม่ได้ลดลงในความคิดเห็นที่จะตอบว่าขอให้ข้อมูลที่ผมคิดว่ามันจะมีการช่วยเหลือทั่วไปในการเขียนโปรแกรมต่อไปนี้ Q & A ที่จะเข้าใจสิ่งที่หมายโดยระยะคุณลักษณะอิจฉา โปรดแก้ไขแท็กเพิ่มเติมหากคุณคิดว่าเหมาะสม


คำตอบ:


87

ฟีเจอร์อิจฉาเป็นคำที่ใช้อธิบายสถานการณ์ที่วัตถุหนึ่งได้รับที่สาขาของวัตถุอื่นเพื่อทำการคำนวณหรือตัดสินใจบางอย่างแทนที่จะขอให้วัตถุทำการคำนวณเอง

เป็นตัวอย่างเล็กน้อยพิจารณาชั้นเรียนที่เป็นตัวแทนของสี่เหลี่ยมผืนผ้า ผู้ใช้สี่เหลี่ยมอาจจำเป็นต้องทราบพื้นที่ของมัน โปรแกรมเมอร์สามารถเปิดเผยwidthและheightเขตข้อมูลจากนั้นทำการคำนวณนอกRectangleชั้นเรียน อีกวิธีหนึ่งคือRectangleสามารถเก็บwidthและheightฟิลด์เป็นส่วนตัวและให้getAreaวิธีการ นี่เป็นวิธีการที่ดีกว่า

ปัญหากับสถานการณ์แรกและเหตุผลที่ถือว่าเป็นกลิ่นรหัสเป็นเพราะมันแบ่ง encapsulation

ตามกฎของหัวแม่มือเมื่อใดก็ตามที่คุณพบว่าตัวเองใช้ประโยชน์จากฟิลด์จากคลาสอื่นเพื่อทำการเรียงลำดับของตรรกะหรือการคำนวณใด ๆ ให้พิจารณาการย้ายตรรกะนั้นไปยังวิธีการในคลาสนั้น


7
+1 แม้ว่าตัวอย่างของคุณจะไม่เหมือนจริงเนื่องจากคลาสสี่เหลี่ยมผืนผ้าที่มีประโยชน์โดยทั่วไปจะเปิดเผยฟิลด์ความกว้างและความสูง
Doc Brown

2
และถึงแม้ว่าการทำลายของการห่อหุ้มอาจเกิดขึ้นพร้อมกับ "Feature Envirism" แต่ในตัวอย่างที่แท้จริงในโลกแห่งความเป็นจริงที่ฉันเคยเห็นมามันก็อาจจะไม่เป็นเช่นนั้น มันเกิดขึ้นมากกว่าในสถานการณ์ "เฮ้ฉันต้องคำนวณบางอย่างในรหัสโดยใช้วัตถุนั้นและฉันไม่แน่ใจว่าฉันสามารถสัมผัสการใช้งานของวัตถุนั้น / ถ้าเราควรให้ความรับผิดชอบแก่วัตถุในการคำนวณ" และจากนั้นหนึ่งในการดำเนินการคำนวณโดยใช้เขตข้อมูลที่มีการสัมผัสแล้ว (แม้ว่าการดำเนินการทำความสะอาดมากอาจจะเป็นไปได้ภายในวัตถุ)
Doc Brown

2
@DocBrown ลองนึกภาพสี่เหลี่ยมผืนผ้าที่ถูกวาดลงบนพื้นผิวของพรูกรวยหรือทรงกลม หากห้องสมุดรูปวาดของฉันสร้างวัตถุที่สามารถสร้างผลลัพธ์ที่ถูกต้องในบริบทดังกล่าวคุณจะโง่ที่จะไม่ปล่อยให้พวกเขาคำนวณพื้นที่ของตัวเอง - ในบริบทใด ๆ
itsbruce

1
@OskarN .: ตามคำนิยามที่เรากำลังพูดคุยเกี่ยวกับฟังก์ชั่นที่จะจำเป็น เห็นได้ชัดว่าพวกเขาจำเป็นต้องใช้ถ้าคลาสอื่นนำพวกเขาซ้ำแล้วซ้ำอีก
Aaronaught

1
@OskarN .: มันขึ้นอยู่กับ; บางครั้งการตัดสินใจมีความชัดเจนบางครั้งมันเป็นเรื่องของรสนิยมและส่วนใหญ่มักจะเป็นเรื่องของประสบการณ์ ในบทความของคุณมีเหตุผลดีๆที่สกอตต์เมเยอร์สเขียนว่า " บางครั้งมีค่าน้อยกว่า" และเขาใช้เวลาหลายปีกว่าจะเข้าใจว่าจะไม่ใช้
Doc Brown

1

มีสถานการณ์ที่เป็นไปได้เมื่อตกลงที่จะใช้วิธีการ class / struct อื่นอย่างกว้างขวาง - เมื่อ class / struct ของคุณเป็นที่เก็บข้อมูล โดยปกติจะมีเพียงเล็กน้อยที่คุณสามารถทำได้กับข้อมูลนี้โดยไม่มีบริบทภายนอก

คลาสดังกล่าวยังคงสามารถใช้ตรรกะภายในได้ แต่บ่อยครั้งที่มันถูกใช้เป็นคอนเทนเนอร์:

class YourUid {
 public:
  YourUid(int id_in_workplace_, int id_in_living_place_, DB* FBI_database, int id_in_FBI_database);
  bool IsInvalidWorker() const { return id_in_workplace == consts::invalid_id_in_workplace; }
  bool CanMessWith() const { return !FBI_database_.is_cool(id_in_FBI_database_); }
  int id_in_workplace;
  int id_in_living_place;
 private:
  int id_in_FBI_database_;
  const DB* FBI_database_;
};

@ jhewlett ในคำตอบของเขาอ้างถึงบทความนี้เพื่อพิสูจน์ว่าคุณไม่ควรใช้สมาชิกชั้นเรียนคนอื่น ๆ อย่างกว้างขวาง แต่มีสถานการณ์รหัสกลิ่นอื่นที่อธิบายไว้ที่นั่นพร้อมกับตัวอย่างของฉัน:

รายการพารามิเตอร์แบบยาว จำกัด จำนวนพารามิเตอร์ที่คุณต้องการในวิธีการที่กำหนดหรือใช้วัตถุเพื่อรวมพารามิเตอร์


1
คำถามนี้ถามคำถามนี้อย่างไร
ริ้น

@gnat คำถามเกี่ยวกับเหตุใดจึงถือเป็น "รหัสกลิ่น" jhewlett ให้ A พร้อมกับข้อสันนิษฐานทั่วไปที่ถามในความคิดเห็น คำตอบของฉันคือ 2 เซ็นต์เพื่อแยก "กลิ่นรหัส" จากการปฏิบัติตามปกติ
ริกา
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.