มันโอเคที่จะต่อต้านการตั้งชื่อตัวพิมพ์ใหญ่ทั้งหมดสำหรับ enums เพื่อให้การแสดงสตริงของพวกเขาง่ายขึ้นหรือไม่?


14

หลายครั้งที่ฉันเห็นคนใช้ตัวพิมพ์ชื่อเรื่องหรือแม้แต่การตั้งชื่อตัวพิมพ์เล็กทั้งหมดสำหรับค่าคงที่ enum ตัวอย่างเช่น:

enum Color {
  red,
  yellow,
  green;
}

สิ่งนี้ทำให้การทำงานกับสตริงเป็นเรื่องง่ายและง่ายthrow new IllegalStateException("Light should not be " + color + ".")ตัวอย่างเช่นถ้าคุณต้องการทำ

ดูเหมือนว่าจะยอมรับได้มากกว่านี้ถ้า Enum เป็นprivateแต่ฉันก็ยังไม่ชอบ ฉันรู้ว่าฉันสามารถสร้างตัวสร้าง enum ด้วยเขตข้อมูล String แล้วแทนที่ toString เพื่อคืนชื่อดังกล่าวดังนี้

enum Color {
  RED("red"),
  YELLOW("yellow"),
  GREEN("green");

  private final String name;

  private Color(String name) { 
    this.name = name 
  }

  @Override public String toString() {
    return name; 
  }
}

แต่ดูว่ามันนานแค่ไหน มันน่ารำคาญที่จะทำต่อไปถ้าคุณมีเงินจำนวนน้อยที่คุณต้องการทำให้เป็นเรื่องง่าย มันจะโอเคไหมที่จะใช้รูปแบบเคสที่ไม่เป็นทางการที่นี่?


4
มันเป็นแบบแผน คุณมีเหตุผลที่จะทำลายการประชุมหรือไม่? ขึ้นอยู่กับคุณ

9
Light should not be RED.เพียงแค่สงสัยว่ามีอะไรผิดปกติกับข้อความแสดงข้อยกเว้นที่ระบุว่า หลังจากทั้งหมดข้อความนี้มีไว้สำหรับนักพัฒนาผู้ใช้ไม่ควรเห็นมัน
Brandin

1
@Brandin ถ้ารายละเอียดการใช้งานมากกว่าสีแล้วก็ไม่มีใครเห็น แน่นอนแล้วฉันเดาว่าจะทิ้งคำถามที่ว่าทำไมเราถึงต้องมีฟอร์ม toString ที่ดี
codebreaker

8
ในตอนท้ายของวันขึ้นอยู่กับคุณ ถ้าฉันแก้จุดบกพร่องรหัสของคุณและเห็นข้อความข้อยกเว้นLight should not be YELLOW.ฉันคิดว่ามันคงที่บางชนิดวิธี toString () เป็นเพียงเพื่อจุดประสงค์ในการตรวจแก้จุดบกพร่องดังนั้นฉันไม่เห็นว่าทำไมคุณต้องเปลี่ยนลักษณะที่ปรากฏในข้อความนั้น
Brandin

1
ฉันคิดว่าคำตอบนั้นขึ้นอยู่กับความคิดของคุณ 'โอเค' โลกเป็นไปได้มากที่สุดที่จะไม่ลุกเป็นไฟถ้าคุณทำเช่นนี้และคุณสามารถเขียนโปรแกรมได้สำเร็จ มันมีประโยชน์หรือไม่ ฉันคิดว่าตัวเองเกินไป หากคุณได้รับผลประโยชน์มันคุ้มค่ากับคุณหรือไม่และจะส่งผลกระทบต่อผู้อื่นหรือไม่ นี่คือคำถามที่ฉันสนใจ
Garet Claborn

คำตอบ:


14

แน่นอนว่าคำตอบสั้น ๆ คือไม่ว่าคุณต้องการทำลายการตั้งชื่อแบบแผนสำหรับสิ่งที่เป็นค่าคงที่ ... การอ้างอิงจากJLS :

ชื่อคงที่

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

คำตอบที่ยาวเกี่ยวกับการใช้toString()คือเป็นวิธีการแทนที่ถ้าคุณต้องการการแสดงค่าที่อ่านได้ง่ายขึ้น enumอ้างจากObject.toString()(เน้นเหมือง):

ส่งคืนการแทนค่าสตริงของวัตถุ โดยทั่วไปtoStringวิธีการส่งกลับสตริงที่ "textually หมายถึง" วัตถุนี้ ผลที่ควรจะเป็นที่กระชับ แต่การแสดงข้อมูลที่เป็นเรื่องง่ายสำหรับคนที่จะอ่าน ขอแนะนำให้คลาสย่อยทั้งหมดแทนที่วิธีนี้

ตอนนี้ฉันไม่แน่ใจว่าทำไมบางคำตอบลอยที่จะพูดคุยเกี่ยวกับการแปลงenumsไปและไปๆมาๆมีStringค่า แต่ฉันก็จะให้เวลาของฉันที่นี่เช่นกัน การทำให้เป็นอันดับของenumค่าดังกล่าวสามารถดูแลได้ง่ายโดยใช้วิธีการname()หรือ ordinal()ทั้งสองfinalและทำให้คุณสามารถตรวจสอบค่าส่งกลับตราบเท่าที่ชื่อหรือการวางตำแหน่งของค่าที่ไม่เปลี่ยนแปลง สำหรับฉันนั่นเป็นเครื่องหมายที่ชัดเจนเพียงพอ

สิ่งที่ฉันรวบรวมจากด้านบนคือ: วันนี้คุณอาจต้องการอธิบายYELLOWว่า "สีเหลือง" อย่างง่ายๆ พรุ่งนี้คุณอาจต้องการที่จะอธิบายว่ามันเป็น"Pantone สมุนสีเหลือง" คำอธิบายเหล่านี้ควรจะกลับมาจากการโทรtoString()และฉันจะไม่คาดหวังอย่างใดอย่างหนึ่งname()หรือordinal()มีการเปลี่ยนแปลง ถ้าฉันทำนั่นเป็นสิ่งที่ฉันจำเป็นต้องแก้ไขภายใน codebase หรือทีมของผมและจะกลายเป็นคำถามที่มากกว่าเพียงแค่enumรูปแบบการตั้งชื่อ

สรุปได้ว่าถ้าสิ่งที่คุณตั้งใจจะทำคือการเข้าสู่ระบบมากขึ้นที่สามารถอ่านได้เป็นตัวแทนของคุณค่าฉันจะยังคงแนะนำให้เลือกใช้การประชุมแล้วเอาชนะenum toString()หากคุณยังตั้งใจที่จะเป็นอันดับพวกเขาเข้าไปในแฟ้มข้อมูลหรือไปยังสถานที่อื่น ๆ ที่ไม่ใช่ Java คุณยังคงมีname()และวิธีการที่จะกลับคุณได้จึงมีไม่จำเป็นต้องกลุ้มกว่าเอาชนะordinal()toString()


5

อย่าแก้ไขENUMนั่นเป็นเพียงกลิ่นรหัสที่ไม่ดี ให้ enum เป็น enum และ string เป็น string

ให้ใช้ตัวแปลง CamelCase แทนสำหรับค่าสตริง

throw new IllegalStateException("Light should not be " + CamelCase(color) + ".");

มีโอเพ่นซอร์สไลบรารีมากมายที่แก้ปัญหานี้สำหรับ Java แล้ว

http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/CaseFormat.html


ในกรณีขอบบางแบบนั้นจะไม่ใช่แบบไม่แน่นอนหรือ (ไม่ใช่พฤติกรรมของตัวแปลงที่เฉพาะเจาะจง แต่เป็นหลักการทั่วไป)
Panzercrisis

-1 การเพิ่มไลบรารี่ของบุคคลที่สามที่อาจไม่ใช่สิ่งที่คุณต้องการสำหรับการจัดรูปแบบสตริงขั้นพื้นฐานอาจเกินความจำเป็น
user949300

1
@ user949300 คัดลอกรหัสเขียนของคุณเองหรืออะไรก็ตาม คุณไม่มีจุด
Reactgular

คุณสามารถอธิบายรายละเอียดเกี่ยวกับ "จุด" หรือไม่? "ให้ enum เป็น enum และ string เป็น string" ฟังดูดี แต่มันหมายถึงอะไรจริง ๆ ?
user949300

1
Enum ให้ความปลอดภัยประเภท เขาไม่สามารถส่งผ่าน "potatoe" เป็นสี และบางทีเขาอาจรวมข้อมูลอื่น ๆ ใน enum เช่นค่า thr RGB เพียงแค่ไม่แสดงในรหัส มีเหตุผลที่ดีมากมายในการใช้ enum แทนที่จะเป็นสตริง
user949300

3

การส่ง enums ระหว่างโค้ด Java ของฉันและแอปฐานข้อมูลหรือไคลเอนต์ฉันมักจะจบลงด้วยการอ่านและเขียนค่า enum เป็นสตริง toString()เรียกว่าปริยายเมื่อเชื่อมสตริง การเอาชนะ toString () ในบาง enums หมายความว่าบางครั้งฉันก็ทำได้

"<input type='checkbox' value='" + MY_CONST1 + "'>"

และบางครั้งฉันก็จำได้ว่าต้องโทร

"<input type='checkbox' value='" + MY_CONST1.name() + "'>"

ซึ่งนำไปสู่ข้อผิดพลาดดังนั้นฉันจะไม่ทำเช่นนั้นอีก ที่จริงแล้วฉันไม่ได้แทนที่วิธีการใด ๆใน Enum เพราะถ้าคุณโยนรหัสลูกค้าให้มากพอคุณจะทำลายความคาดหวังของใครบางคนในที่สุด

ทำให้ชื่อของวิธีการใหม่ของคุณเองเช่นpublic String text()หรือtoEnglish()หรืออะไรก็ตาม

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

public static String ucFirstLowerRest(String s) {
    if ( (s == null) || (s.length() < 1) ) {
        return s;
    } else if (s.length() == 1) {
        return s.toUpperCase();
    } else {
        return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
    }
}

เป็นเรื่องง่ายที่จะโทรหา. toUpperCase () หรือ. toLowerCase () แต่การเรียกคืนตัวพิมพ์เล็กอาจยุ่งยาก พิจารณาสี "bleu de France" ฝรั่งเศสมีตัวพิมพ์ใหญ่เสมอดังนั้นคุณอาจต้องการเพิ่มวิธี textLower () ลงใน enum ของคุณหากคุณพบเจอ เมื่อคุณใช้ข้อความนี้ที่จุดเริ่มต้นของประโยคเทียบกับตรงกลางของประโยคเทียบกับในชื่อคุณจะเห็นว่าวิธีการเดียวtoString()จะสั้นลง และนั่นไม่แม้แต่จะแตะตัวอักษรที่ผิดกฎหมายในตัวระบุ Java หรือนั่นเป็นความเจ็บปวดที่จะพิมพ์เพราะมันไม่ได้แสดงบนแป้นพิมพ์มาตรฐานหรือตัวอักษรที่ไม่มีตัวพิมพ์ (คันจิเป็นต้น)

enum Color {
  BLEU_DE_FRANCE {
    @Override public String textTc() { return "Bleu De France"; }
    @Override public String textLc() { return "bleu de France"; }
  }
  CAFE_NOIR {
    @Override public String textTc() { return "Café Noir"; }
  }
  RED,
  YELLOW,
  GREEN;

  // The text in title case
  private final String textTc;

  private Color() { 
    textTc = ucFirstLowerRest(this.toString());
  }

  // Title case
  public String textTc() { return textTc; }

  // For the middle of a sentence
  public String textLc() { return textTc().toLowerCase(); }

  // For the start of a sentence
  public String textUcFirst() {
    String lc = textLc();
    return lc.substring(0, 1).toUpperCase() + lc.substring(1);
  }
}

การใช้สิ่งเหล่านี้อย่างไม่ยาก:

IllegalStateException(color1.textUcFirst() + " clashes horribly with " +
                      color2.textLc() + "!")

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


3
ข้อเสนอแนะที่จะไม่แทนที่toString()enum ไม่สมเหตุสมผลสำหรับฉัน ถ้าคุณต้องการให้การทำงานเริ่มต้นการรับประกันของชื่อ enum name()ใช้ ผมพบว่ามันไม่ "ดึงดูด" ที่ทุกคนต้องพึ่งพาเพื่อให้คีย์ที่ถูกต้องสำหรับtoString() valueOf(String)ผมคิดว่าถ้าคุณต้องการที่จะโง่หลักฐาน enums ของคุณที่สิ่งหนึ่ง แต่ผมไม่คิดว่านั่นเป็นเหตุผลที่ดีพอที่จะแนะนำว่าคุณควรจะไม่toString()แทนที่
codebreaker

1
นอกจากนี้ฉันพบสิ่งนี้ซึ่งแนะนำ (ตามที่ฉันถูกนำไปสู่ความเชื่อ) ว่าการเอาชนะ toString on enums นั้นเป็นสิ่งที่ดีจริง ๆ : stackoverflow.com/questions/13291076/…
codebreaker

@codebreaker toString () เรียกว่าปริยายเมื่อทำการต่อสตริง การเอาชนะ toString () ในบาง enums หมายความว่าบางครั้งฉันก็ทำได้<input type='checkbox' value=" + MY_CONST1 + ">และบางครั้งฉันก็ต้องจำสาย<input type='checkbox' value=" + MY_CONST1.name() + ">ซึ่งนำไปสู่ข้อผิดพลาด
GlenPeterson

โอเคนั่นเป็นจุดที่ดี แต่สำคัญมากเมื่อคุณ "ซีเรียลไลซ์" กับชื่อของพวกเขา (ซึ่งไม่ใช่สิ่งที่ฉันต้องกังวลเกี่ยวกับตัวอย่างของฉัน)
codebreaker

0

หากมีโอกาสน้อยที่สุดที่การแทนค่าสตริงเหล่านี้อาจถูกเก็บไว้ในสถานที่เช่นฐานข้อมูลหรือไฟล์ข้อความการผูกมันไว้กับค่าคงที่ enum จริงจะกลายเป็นปัญหาอย่างมากหากคุณจำเป็นต้อง refactor enum ของคุณ

ถ้าวันหนึ่งคุณตัดสินใจเปลี่ยนชื่อColor.Whiteเป็นColor.TitaniumWhiteในขณะที่มีไฟล์ข้อมูลที่มี "สีขาว" อยู่ล่ะ

นอกจากนี้เมื่อคุณเริ่มการแปลงค่าคงที่ enum เป็นสตริงขั้นตอนต่อไปที่อยู่ข้างถนนจะเป็นการสร้างสตริงเพื่อให้ผู้ใช้เห็นและปัญหาที่นี่คือผมมั่นใจว่าคุณรู้แล้วว่าไวยากรณ์ของ java ไม่ได้ อนุญาตให้มีช่องว่างภายในตัวระบุ (คุณจะไม่มีวันColor.Titanium White) ดังนั้นเนื่องจากคุณอาจต้องการกลไกที่เหมาะสมในการสร้างชื่อ enum เพื่อแสดงต่อผู้ใช้จึงเป็นการดีที่สุดที่จะหลีกเลี่ยงการทำให้ enum ของคุณมีความซับซ้อนโดยไม่จำเป็น

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

คุณสามารถโกนสองบรรทัดออกจาก enum-with-constructor ของคุณโดยการประกาศnameฟิลด์public finalและสูญเสียทะเยอทะยาน (ความรักนี้ที่โปรแกรมเมอร์ Java มีต่อ getters คืออะไร)


สแตติกสุดท้ายสาธารณะได้รับการรวบรวมเป็นรหัสที่ใช้มันเป็นค่าคงที่ที่เกิดขึ้นจริงมากกว่าการอ้างอิงถึงระดับที่มาจาก สิ่งนี้สามารถทำให้เกิดข้อผิดพลาดความสนุกอื่น ๆ ได้หลายอย่างเมื่อทำการคอมไพล์ซ้ำบางส่วนของโค้ด (หรือแทนที่ไห) หากคุณกำลังแนะนำpublic final static int white = 1;หรือpublic final static String white = "white";(นอกเหนือจากการหยุดการประชุมอีกครั้ง) สิ่งนี้จะสูญเสียความปลอดภัยของประเภทที่ enum ให้ไว้

@MichaelT ฟิลด์ Enum ไม่คงที่ อินสแตนซ์ถูกสร้างขึ้นสำหรับค่าคงที่แต่ละ enum และสมาชิกของ enum เป็นตัวแปรสมาชิกของอินสแตนซ์นั้น public finalฟิลด์อินสแตนซ์ที่ได้รับการเริ่มต้นจากพฤติกรรมคอนสตรัคเหมือนกับข้อมูลที่ไม่ใช่สุดท้ายยกเว้นว่าคุณจะมีการป้องกันที่รวบรวมเวลาจากการกำหนดให้กับมัน คุณสามารถแก้ไขได้ผ่านการสะท้อนและรหัสทั้งหมดที่อ้างถึงจะเริ่มเห็นค่าใหม่ทันที
Mike Nakis

0

เนื้อหาดังต่อไปนี้การประชุมพิมพ์ใหญ่ตั้งชื่อละเมิดแห้ง (และYAGNI ) เช่นในตัวอย่างรหัสของคุณ # 2: "RED" และ "red" จะถูกทำซ้ำ

ดังนั้นคุณทำตามการประชุมอย่างเป็นทางการหรือติดตาม DRY? การโทรของคุณ

ในรหัสของฉันฉันจะติดตาม DRY อย่างไรก็ตามฉันจะใส่ความคิดเห็นในคลาส Enum โดยพูดว่า "ไม่ใช่ตัวพิมพ์ใหญ่ทั้งหมดเพราะ (คำอธิบายที่นี่)"

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