ความหมายของ 'การติดต่อกันสูง' คืออะไร?


28

ฉันเป็นนักเรียนที่เพิ่งเข้าร่วม บริษัท พัฒนาซอฟต์แวร์เพื่อฝึกงาน กลับไปที่มหาวิทยาลัยอาจารย์คนหนึ่งของฉันเคยบอกว่าเราต้องพยายามให้ได้ "การมีเพศสัมพันธ์ต่ำและการทำงานร่วมกันสูง"

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

แต่สิ่งที่มีความหมายโดยการทำงานร่วมกันสูง ถ้ามันหมายถึงการรวมส่วนประกอบต่าง ๆ ของส่วนประกอบเดียวกันเข้าด้วยกันฉันไม่เข้าใจว่ามันจะมีประโยชน์อย่างไร

การรวมกันสูงหมายถึงอะไร ตัวอย่างสามารถอธิบายให้เข้าใจถึงประโยชน์ของมันได้หรือไม่



1
บทความวิกิพีเดียไม่ตอบคำถามของคุณอย่างเพียงพอหรือไม่? en.wikipedia.org/wiki/Cohesion_(computer_science)
Eoin Carroll

มีบทความที่ดีเกี่ยวกับเรื่องนี้ได้ที่: msdn.microsoft.com/en-us/magazine/cc947917.aspx
NoChance

1
@EoinCarroll: น่าเสียดายที่บทความวิกิพีเดียในขณะนี้ไม่ได้ให้ตัวอย่างที่เป็นรูปธรรมใด ๆที่โปรแกรมเมอร์ใหม่สามารถทำงานได้ ทฤษฎีเป็นสิ่งที่ดี แต่ไม่ติดจนกว่าคุณจะทำผิดพลาดโดยรอบการทำงานร่วมกันต่ำ การทำงานร่วมกันสูงเป็นหนึ่งในหัวข้อเหล่านั้นที่ใช้เวลาหลายปีในการเขียนโปรแกรมเพื่อทำความเข้าใจว่าเหตุใดจึงมีความสำคัญและวิธีการทำให้สำเร็จ
Spoike

ฉันไม่เคยเข้าใจการทำงานร่วมกันจริงๆจนกว่าฉันจะอ่าน Clean Code คุณควรทำเช่นกัน
เซบาสเตียนเรดล

คำตอบ:


25

วิธีหนึ่งในการดูการทำงานร่วมกันในแง่ของ OO คือถ้าวิธีการในชั้นเรียนกำลังใช้คุณลักษณะส่วนตัวใด ๆ การใช้ตัวชี้วัดเช่น LCOM4 (วิธีที่ไม่ยึดติดกัน) ตามที่ gnat ชี้ให้เห็นในคำตอบนี้ที่นี่คุณสามารถระบุคลาสที่สามารถปรับโครงสร้างใหม่ได้ เหตุผลที่คุณต้องการวิธีการ refactor หรือชั้นเรียนที่จะเหนียวมากขึ้นก็คือว่ามันทำให้โค้ดการออกแบบที่เรียบง่ายสำหรับคนอื่น ๆ ที่จะใช้มัน เชื่อฉัน; ผู้นำด้านเทคโนโลยีส่วนใหญ่และโปรแกรมเมอร์บำรุงรักษาจะรักคุณเมื่อคุณแก้ไขปัญหาเหล่านี้

คุณสามารถใช้เครื่องมือในกระบวนการสร้างเช่นSonarเพื่อระบุการทำงานร่วมกันในระดับต่ำในฐานรหัส มีบางกรณีที่พบบ่อยมากที่ฉันสามารถนึกถึงวิธีการที่ต่ำใน"cohesiveness" :

กรณีที่ 1: วิธีการไม่เกี่ยวข้องกับคลาสเลย

ลองพิจารณาตัวอย่างต่อไปนี้:

public class Food {
   private int _foodValue = 10;

   public void Eat() {
     _foodValue -= 1;
   }

   public void Replenish() {
     _foodValue += 1;
   }

   public void Discharge() {
     Console.WriteLine("Nnngghhh!");
   }
}

หนึ่งในวิธีการที่Discharge()ขาดการติดต่อกันเพราะมันไม่ได้สัมผัสสมาชิกส่วนตัวของชั้นเรียน ในกรณีนี้มีสมาชิกส่วนตัวเพียงคนเดียวเท่านั้น: _foodValue. ถ้ามันไม่ได้ทำอะไรกับผู้ฝึกหัดในชั้นเรียนแล้วมันมีอยู่จริงหรือเปล่า? FoodDischargerวิธีการที่จะถูกย้ายไปยังชั้นอื่นที่อาจจะตั้งชื่อเช่น

// Non-cohesive function extracted to another class, which can
// be potentially reused in other contexts
public FoodDischarger {
  public void Discharge() {
    Console.WriteLine("Nnngghhh!");
  }
}

เมื่อคุณทำเช่นนี้ใน Javascript เนื่องจากฟังก์ชั่นเป็นวัตถุชั้นหนึ่งการปลดประจำการอาจเป็นฟังก์ชั่นฟรี:

function Food() {
    this._foodValue = 10;
}
Food.prototype.eat = function() {
    this._foodValue -= 1;
};
Food.prototype.replenish = function() {
    this._foodValue += 1;
};

// This
Food.prototype.discharge = function() {
    console.log('Nnngghhh!');
};
// can easily be refactored to:
var discharge = function() {
    console.log('Nnngghhh!');
};
// making it easily reusable without creating a class

กรณีที่ 2: คลาสยูทิลิตี้

นี่เป็นกรณีทั่วไปที่แบ่งการทำงานร่วมกัน ทุกคนชอบคลาสยูทิลิตี้ แต่สิ่งเหล่านี้มักจะบ่งบอกถึงข้อบกพร่องในการออกแบบและส่วนใหญ่แล้วทำให้ codebase มีเล่ห์เหลี่ยมในการรักษา (เพราะการพึ่งพาสูงที่เกี่ยวข้องกับคลาสยูทิลิตี้) พิจารณาคลาสต่อไปนี้:

public class Food {
    public int FoodValue { get; set; }
}

public static class FoodHelper {

    public static void EatFood(Food food) {
        food.FoodValue -= 1;
    }

    public static void ReplenishFood(Food food) {
        food.FoodValue += 1;
    }

}

Foodที่นี่เราจะเห็นว่าระดับยูทิลิตี้ความต้องการที่จะเข้าถึงสถานที่ให้บริการในชั้นเรียน วิธีการในคลาสยูทิลิตี้ไม่มีการทำงานร่วมกันเลยในกรณีนี้เพราะมันต้องการทรัพยากรภายนอกเพื่อให้มันทำงาน ในกรณีนี้มันจะดีกว่าหรือไม่ที่จะมีวิธีการในชั้นเรียนที่พวกเขาทำงานด้วยตัวเอง (เหมือนในกรณีแรก)?

กรณีที่ 2b: วัตถุที่ซ่อนอยู่ในคลาสยูทิลิตี้

มีอีกกรณีหนึ่งของคลาสยูทิลิตี้ที่มีวัตถุโดเมนที่ไม่เกิดขึ้นจริง ปฏิกิริยาการกระตุกเข่าแรกที่โปรแกรมเมอร์มีเมื่อการเขียนโปรแกรมการจัดการสตริงคือการเขียนคลาสยูทิลิตี้สำหรับมัน เช่นเดียวกับที่นี่ซึ่งตรวจสอบความถูกต้องของการแสดงสตริงร่วมกันสองรายการ:

public static class StringUtils {

  public static bool ValidateZipCode(string zipcode) {
    // validation logic
  }

  public static bool ValidatePhoneNumber(string phoneNumber) {
    // validation logic
  }

}

สิ่งที่คนส่วนใหญ่ไม่ทราบที่นี่คือรหัสไปรษณีย์หมายเลขโทรศัพท์หรือการนำเสนอสตริงอื่น ๆ สามารถเป็นวัตถุได้:

public class ZipCode {
    private string _zipCode;
    public bool Validates() {
      // validation logic for _zipCode
    }
}

public class PhoneNumber {
    private string _phoneNumber;
    public bool Validates() {
      // validation logic for _phoneNumber
    }
}

ความคิดที่คุณไม่ควร "จัดการสตริง" โดยตรงมีรายละเอียดในบล็อกนี้โดย @codemonkeyismแต่มีความสัมพันธ์อย่างใกล้ชิดกับการทำงานร่วมกันเพราะวิธีที่โปรแกรมเมอร์ใช้สตริงโดยใส่ตรรกะในคลาสยูทิลิตี้


ตอนนี้ถ้าเพียง แต่เราสามารถรับ ORMs ของเราเพื่อจัดการคลาส ZipCode และ PhoneNumber ที่กำหนดเองของเรา: |
Pete

+1 ตัวอย่างที่ดี สำหรับประเด็นสุดท้ายดูที่sourcemaking.com/refactoring/primitive-obsession
AlexFoxGill

@Peat ORM ของคุณจะจัดการหากคุณให้บริการตัวดำเนินการแปลงจากสตริงไปเป็นประเภทที่คุณกำหนด ( ZipCode
Marcus

9

วิธีการทำงานร่วมกันสูงเพื่อให้สิ่งที่คล้ายกันและที่เกี่ยวข้องร่วมกันเพื่อคู่รักหรือฟิวส์ชิ้นส่วนซึ่งเนื้อหาส่วนแบ่งการทำงานหรือเหตุผลเป้าหมาย กล่าวอีกนัยหนึ่งการทำงานร่วมกันในระดับต่ำอาจหมายถึงเอนทิตีฟังก์ชัน / คลาส / รหัสซึ่งให้บริการหลายวัตถุประสงค์แทนที่จะเป็น " ถึงจุด " หนึ่งในความคิดการดำเนินการคือการทำสิ่งหนึ่งและทำมันได้ดี คนอื่น ๆ อาจรวมถึงข้อเท็จจริงที่ชัดเจนว่าคุณไม่ได้จำลองฟังก์ชั่นที่คล้ายกันในหลาย ๆ ที่ นอกจากนี้ยังช่วยเพิ่มท้องที่ของฐานรหัสบางชนิดของสิ่งที่พบในสถานที่บางอย่าง (ไฟล์ชั้นตั้งฟังก์ชั่น, ... ) มากกว่าการกระจายอยู่ทั่ว

เป็นตัวอย่างให้พิจารณาคลาสที่ทำหน้าที่สองหรือสามวัตถุประสงค์: โหลด / เก็บทรัพยากร (เช่นไฟล์) จากนั้นทำการวิเคราะห์และแสดงเนื้อหา คลาสดังกล่าวมีการติดต่อกันต่ำเพราะจัดการอย่างน้อยสองงานที่ไม่เกี่ยวข้องเลย (ไฟล์ I / O, การวิเคราะห์และการแสดงผล) การออกแบบที่เชื่อมโยงกันสูงสามารถใช้คลาสที่แตกต่างกันสำหรับการโหลดและการจัดเก็บทรัพยากรการวิเคราะห์และจากนั้นแสดงมัน

ในขณะที่การมีเพศสัมพันธ์ต่ำมีจุดมุ่งหมายเพื่อแยกสิ่งที่แตกต่าง - เพื่อให้พวกเขามีปฏิสัมพันธ์กันน้อยที่สุดซึ่งจะช่วยลดความซับซ้อนและลดความซับซ้อนและลดความซับซ้อนของการออกแบบ


7

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


มันใช้กับระดับที่สูงกว่าวัตถุไม่ได้หรือ เช่นการจัดกลุ่ม objcts / ฟังก์ชั่นที่เกี่ยวข้องกับงานใน namespaces หรือไม่?
stijn
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.