แทนที่รหัสประเภทด้วยคลาส (จาก Refactoring [Fowler])


9

กลยุทธ์นี้เกี่ยวข้องกับการแทนที่สิ่งนี้:

public class Politician
{
    public const int Infidelity = 0;
    public const int Embezzlement = 1;
    public const int FlipFlopping = 2;
    public const int Murder = 3;
    public const int BabyKissing = 4;

    public int MostNotableGrievance { get; set; }
}

ด้วย:

public class Politician
{
    public MostNotableGrievance MostNotableGrievance { get; set; }
}

public class MostNotableGrievance
{
    public static readonly MostNotableGrievance Infidelity = new MostNotableGrievance(0);
    public static readonly MostNotableGrievance Embezzlement = new MostNotableGrievance(1);
    public static readonly MostNotableGrievance FlipFlopping = new MostNotableGrievance(2);
    public static readonly MostNotableGrievance Murder = new MostNotableGrievance(3);
    public static readonly MostNotableGrievance BabyKissing = new MostNotableGrievance(4);

    public int Code { get; private set; }

    private MostNotableGrievance(int code)
    {
        Code = code;
    }
}

เหตุใดจึงเป็นการดีกว่าที่จะทำให้การระบุประเภทเช่น:

public class Politician
{
    public MostNotableGrievance MostNotableGrievance { get; set; }
}

public enum MostNotableGrievance
{
    Infidelity = 0,
    Embezzlement = 1,
    FlipFlopping = 2,
    Murder = 3,
    BabyKissing = 4
}

ไม่มีพฤติกรรมที่เกี่ยวข้องกับประเภทและหากคุณต้องการใช้การปรับโครงสร้างชนิดอื่น ๆ เช่น 'แทนที่รหัสประเภทด้วยคลาสย่อย' + 'แทนที่เงื่อนไขด้วยความหลากหลาย'

อย่างไรก็ตามผู้เขียนอธิบายว่าทำไมเขาถึงขมวดคิ้วกับวิธีนี้ (ใน Java?):

รหัสประเภทตัวเลขหรือการแจกแจงเป็นคุณสมบัติทั่วไปของภาษาที่ใช้ภาษา C ด้วยชื่อสัญลักษณ์พวกเขาสามารถอ่านได้ค่อนข้าง ปัญหาคือชื่อสัญลักษณ์เป็นเพียงนามแฝง คอมไพเลอร์ยังคงเห็นหมายเลขพื้นฐาน ประเภทคอมไพเลอร์ตรวจสอบโดยใช้หมายเลข 177 ไม่ใช่ชื่อสัญลักษณ์ วิธีการใด ๆ ที่ใช้รหัสประเภทเป็นอาร์กิวเมนต์คาดว่าตัวเลขและไม่มีอะไรที่จะบังคับให้ใช้ชื่อสัญลักษณ์ สิ่งนี้สามารถลดความสามารถในการอ่านและเป็นแหล่งของข้อบกพร่อง

แต่เมื่อพยายามที่จะใช้คำสั่งนี้กับ C # คำสั่งนี้ดูเหมือนจะไม่เป็นจริง: มันจะไม่ยอมรับตัวเลขเพราะการแจงนับนั้นจริงๆแล้วถือว่าเป็นคลาส ดังนั้นรหัสต่อไปนี้:

public class Test
{
    public void Do()
    {
        var temp = new Politician { MostNotableGrievance = 1 };
    }
}

จะไม่รวบรวม ดังนั้นการปรับโครงสร้างใหม่นี้จึงอาจถือว่าไม่จำเป็นในภาษาระดับสูงรุ่นใหม่เช่น C # หรือฉันไม่ได้พิจารณาอะไรเลย


var temp = new Politician { MostNotableGrievance = MostNotableGrievance.Embezzlement };
Robert Harvey

คำตอบ:


6

ฉันคิดว่าคุณเกือบจะตอบคำถามของคุณเองที่นั่น

ควรใช้รหัสที่สองในส่วนแรกเนื่องจากเป็นรหัสที่ให้ความปลอดภัย ด้วยชิ้นแรกถ้าคุณมีการแจงนับที่คล้ายกันของปลาคุณก็สามารถพูดได้

MostNotableGrievance grievance = Fish.Haddock;

และคอมไพเลอร์จะไม่สนใจ ถ้า Fish.Haddock = 2 แล้วข้างบนจะเท่ากับ

MostNotableGrievance grievance = MostNotableGrievance.FlipFlopping;

แต่เห็นได้ชัดว่าไม่สามารถอ่านได้ทันทีเช่นนี้

เหตุผลที่แจกแจงมักจะไม่ดีกว่านั้นเป็นเพราะการแปลงโดยปริยายไปยังและจาก int ทำให้คุณมีปัญหาเดียวกันแน่นอน

แต่ใน C # ไม่มีการแปลงโดยนัยดังกล่าวดังนั้น enum จึงเป็นโครงสร้างที่ดีกว่าที่จะใช้ คุณจะไม่ค่อยเห็นวิธีใดวิธีหนึ่งจากสองวิธีแรกที่ใช้


5

หากไม่มีพฤติกรรมที่เกี่ยวข้องกับค่าและไม่มีข้อมูลเพิ่มเติมที่คุณต้องการจัดเก็บไว้ข้างๆและภาษาไม่รองรับการแปลงเป็นจำนวนเต็มฉันจะใช้ enum นั่นคือสิ่งที่พวกเขามีเพื่อ


1

อีกตัวอย่างหนึ่งที่อาจช่วยคุณได้ในจาวาที่มีประสิทธิภาพ (รายการ 30 ถ้าคุณต้องการค้นหา) มันถูกต้องสำหรับ C # เช่นกัน

สมมติว่าคุณใช้ค่าคงที่ int เพื่อจำลองสัตว์ต่าง ๆ พูดงูและสุนัข

int SNAKE_PYTHON=0;
int SNAKE_RATTLE=1;
int SNAKE_COBRA=2;

int DOG_TERRIER=0;
int DOG_PITBULL=1;

สมมติว่าค่าเหล่านี้เป็นค่าคงที่และอาจกำหนดไว้ในคลาสที่แตกต่างกัน สิ่งนี้อาจดูดีสำหรับคุณและอาจได้ผลจริง แต่พิจารณารหัสบรรทัดนี้:

snake.setType(DOG_TERRIER);

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

snake.setType(0);

จริง ๆ แล้วงูของคุณเป็นงูหลาม (และไม่ใช่เทอร์เรียร์) คุณลักษณะนี้เรียกว่าความปลอดภัยของประเภทและเป็นจริงสาเหตุที่คุณเป็นตัวอย่างรหัส

var temp = new Politician { MostNotableGrievance = 1 };

จะไม่รวบรวม MostNotableGrievance เป็น MostNotableGrievance ไม่ใช่จำนวนเต็ม ด้วย enums คุณสามารถแสดงสิ่งนี้ในระบบประเภท และนั่นคือเหตุผลที่มาร์ตินฟาวเลอร์และฉันคิดว่าการแจกแจงยอดเยี่ยม

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