วิธีหนึ่งในการดูการทำงานร่วมกันในแง่ของ 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แต่มีความสัมพันธ์อย่างใกล้ชิดกับการทำงานร่วมกันเพราะวิธีที่โปรแกรมเมอร์ใช้สตริงโดยใส่ตรรกะในคลาสยูทิลิตี้