วิธีในการรับรองอินสแตนซ์ที่ไม่เหมือนใครของชั้นเรียนหรือไม่?


14

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

ตัวอย่างเช่นผมมีเรียนกับสนามName nameเมื่อฉันมีNameวัตถุที่nameเริ่มต้นให้กับ John Smith ฉันไม่ต้องการที่จะสามารถสร้างอินสแตนซ์ของNameวัตถุที่แตกต่างด้วยชื่อเป็น John Smith หรือถ้าการสร้างอินสแตนซ์เกิดขึ้นฉันต้องการให้มีการอ้างอิงไปยังวัตถุเดิม กว่าวัตถุใหม่

ฉันทราบว่าวิธีหนึ่งในการทำเช่นนี้คือการมีโรงงานแบบคงที่ที่มีMapวัตถุชื่อปัจจุบันทั้งหมดและโรงงานตรวจสอบว่าวัตถุที่มี John Smith เป็นชื่อที่ไม่มีอยู่ก่อนส่งกลับการอ้างอิงไปยังNameวัตถุ.

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

มีวิธีอื่นในการบรรลุเป้าหมายนี้หรือไม่?


1
คุณต้องการซิงเกิล

5
คุณควรไปกับคนแรก: - โรงงานคงที่
Rohit Jain

16
@MarcB op ไม่ต้องการซิงเกิล เขาอาจมีหลายอินสแตนซ์ของคลาสเดียวกัน แต่อินสแตนซ์เหล่านี้ต้องสามารถระบุได้

1
@MarcB ฉันรู้รูปแบบซิงเกิล แต่ฉันคิดว่าจะทำให้แน่ใจว่ามีเพียงคลาสเดียวที่เป็นไปได้? ฉันต้องการอินสแตนซ์หลายค่าที่แตกต่างกัน ขออภัยหากคำถามไม่ชัดเจน แก้ไข: เห็นเฉพาะความคิดเห็นแรกก่อนโพสต์
ถั่วลิสง

2
I'm aware that one way of doing this is to have a static factory that holds a Map...ดังนั้นทำไมคุณไม่ต้องการที่จะทำแบบนี้?
FrustratedWithFormsDesigner

คำตอบ:


13

ที่จริงคุณตอบคำถามแล้ว วิธีแรกของคุณควรมีประสิทธิภาพมากกว่าที่นี่ การใช้static factoryนั้นดีกว่าเสมอconstructorทุกที่ที่คุณคิดว่าคุณทำได้ ดังนั้นคุณสามารถหลีกเลี่ยงการใช้Constructorในกรณีนี้มิฉะนั้นคุณจะมีthrow some exceptionถ้ามีอยู่แล้วด้วยชื่อที่กำหนด

ดังนั้นคุณสามารถสร้างวิธีการคงที่จากโรงงาน: - getInstanceWithName(name)ซึ่งจะได้รับอินสแตนซ์ที่มีอยู่แล้วพร้อมกับชื่อนั้นและหากไม่มีอยู่มันจะสร้างอินสแตนซ์ใหม่และทำให้เป็นconstructorส่วนตัวตามที่ควรทำเมื่อจัดการกับstatic factories.

นอกจากนี้เพื่อที่คุณจะต้องรักษาสแตติกListหรือMapอินสแตนซ์ที่ไม่ซ้ำกันทั้งหมดที่สร้างขึ้นในFactoryชั้นเรียนของคุณ

แก้ไข : -

แน่นอนคุณควรไปถึง - มีประสิทธิภาพชวา - Item # 1: พิจารณาโรงงานแบบคงที่ในช่วงก่อสร้าง คุณไม่สามารถรับคำอธิบายที่ดีกว่าหนังสือเล่มนั้นได้


1
นั่นคือสิ่งที่ OP คิดไว้แล้ว
BGurung

+1 สำหรับลิงค์ซึ่งดูเหมือนจะชัดเจนว่าอยู่ในความกังวลของ OP
Robert Harvey

@RobertHarvey ใช่หนังสือเล่มนั้นเป็นแหล่งข้อมูลที่ดีที่สุดสำหรับหัวข้อส่วนใหญ่เช่นนี้ และนั่นเป็นรายการแรกในความเป็นจริง :)
Rohit Jain

+1 สำหรับ Java ที่มีประสิทธิภาพฉันมีหนังสือนั่งอยู่ในกระเป๋าของฉันตอนนี้จริง ๆ แล้ว :) อย่างไรก็ตามฉันแค่อยากรู้อยากเห็นว่าวิธีอื่น ๆ ในการบรรลุความเป็นเอกลักษณ์นอกเหนือจากวิธีการคงที่โรงงาน / วิธีคงที่และข้อยกเว้นในตัวสร้าง หากไม่มีแล้วฉันจะยอมรับสิ่งนี้
ถั่วลิสง

@Peanut แน่ใจ นั่นคือแหล่งข้อมูลที่ดีที่สุดในการขุดเพื่อรับข้อมูลเพิ่มเติม
Rohit Jain

5

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

  • รายการ Java ที่มีประสิทธิภาพ 8: ปฏิบัติตามสัญญาทั่วไปเมื่อเอาชนะเท่ากับ
  • รายการ Java ที่มีประสิทธิภาพ 9: แทนที่ hashCode ทุกครั้งเมื่อคุณแทนที่เท่ากับ
  • รายการ Java ที่มีประสิทธิภาพ 15: ลดความไม่แน่นอนให้น้อยลง

ฉันจะย้อนกลับไปและตั้งคำถามว่าทำไมคุณถึงสนใจหากมีวัตถุชื่อนี้มากกว่าหนึ่งรายการ

ฉันไม่ค่อยต้องการทำวัตถุชนิดนี้ร่วมกัน มันเป็นฉันเดาว่า OP จะทำเช่นนี้เพื่อให้พวกเขาสามารถเปรียบเทียบพวกเขาวัตถุที่มีName ==หรือใช้NameวัตถุภายในHashMapหรือคล้ายกับกุญแจ

ถ้าเป็นเช่นนี้คือสิ่งที่จะสามารถแก้ไขได้ผ่านการดำเนินการที่เหมาะสมของequals()

ชอบมาก

public final class Name {
  private final String name;

  public Name(String name) {
    if (name == null) {
      name = ""; //or exception if you like
    }
    this.name = name;
  }

  public String getName() {
    return name;
  }

  @Override
  public boolean equals(Object o) {
    if (!(o instanceof Name)) {
      return false;
    }
    Name other = (Name) o;
    return other.name.equals(name);
  }

  @Override
  public int hashCode() {
    return name.hashCode();
  }
}

เมื่อทำต่อไปนี้เป็นจริง:

Name a = new Name("weston");
Name b = new Name("weston");
assert(a.equals(b)); //same but:
assert(a!=b); //not the same instance
//test out the Name instances in a hashmap:
HashMap<Name,Object> map = new HashMap<Name,Object>();
Object detailsIn = new Object();
map.put(a,detailsIn);
Object detailsOut = map.get(b);
assert(detailsIn==detailsOut); //the map returned the same details object
//even though we put with `a` and got with `b` thanks to our correct equals implementation

ฉันเดาเป้าหมายของคุณ แต่วิธีนี้คุณสามารถใช้Nameคลาสในแผนที่แฮชเป็นต้นและพวกเขาไม่จำเป็นต้องเป็นอินสแตนซ์เดียวกันแน่นอน


ตัวอย่างได้โปรด
Robert Harvey

@RobertHarvey ตัวอย่างของการใช้งานที่เหมาะสม?
weston

ดูเหมือนว่าคุณจะให้ แต่ฉันไม่ชัดเจนว่านี่แตกต่างจากการตรวจสอบคุณสมบัติชื่อเพื่อความเท่าเทียมกันในวิธีการคงที่จากโรงงาน
Robert Harvey

1
@ RobertHarvey ฉันพยายามอธิบายให้มากขึ้นฉันกำลังเสนอทางเลือกที่สมบูรณ์แบบที่ไม่ต้องการโรงงานแบบคงที่เลยและฉันกำลังท้าทายจุดเริ่มต้นของ OPs ที่พวกเขาไม่ต้องการมีมากกว่าหนึ่งครั้งต่อชื่อ
weston

เหตุผลที่ถูกต้องในการต้องการวัตถุที่ไม่ซ้ำกันคือถ้าคุณต้องการบล็อกที่ซิงโครไนซ์เพื่อใช้วัตถุเป็นจอภาพ วัตถุสองชิ้นที่. equals () กันและกันจะไม่ทำงาน
Leigh Caldwell

3
  • สร้างNameอินเตอร์เฟส
  • สร้างส่วนต่อประสานNameFactoryด้วยวิธีการName getByName(String)
  • สร้างการใช้งานNameFactoryด้วยMap<String,WeakReference<Name>>ภายใน
  • synchronizeบนแผนที่ตามชื่อภายในgetByNameวิธีการก่อนที่จะสร้างอินสแตนซ์ใหม่ของName
  • อีกทางเลือกหนึ่งให้ใช้การใช้งานส่วนบุคคลแบบคงที่ของNameส่วนติดต่อภายในการใช้NameFactory

วิธีการนี้จะช่วยให้คุณมั่นใจได้ว่า:

  • มีเพียงอินสแตนซ์เดียวเท่านั้นที่มีNameอยู่ตลอดเวลา
  • ไม่มีหน่วยความจำ "Lingerer" ในชั้นเรียนของคุณเมื่อNameติดรอบนานกว่าที่พวกเขาต้องการ
  • การออกแบบยังคงสามารถทดสอบได้กับวัตถุที่เยาะเย้ยเพราะคุณใช้อินเทอร์เฟซ

คุณไม่มีการรั่วไหลของหน่วยความจำด้วยวิธีการจากโรงงานอย่างใดอย่างหนึ่งถ้าคุณthrowเมื่อชื่อที่เหมือนกันอยู่แทนการส่งคืนวัตถุหรือถ้าคุณส่งคืนnullวัตถุ
Robert Harvey

@RobertHarvey ฉันหมายถึงการรั่วไหลที่ไม่รั่วไหลจริงๆ แต่เป็นวัตถุที่ถูกกฎหมาย (ที่เรียกว่า "อิทธิพล") แผนที่แบบสแตติกที่เรียบง่ายจะป้องกันไม่ให้วัตถุค่าของมันถูกปล่อยออกมาในขณะที่แผนที่ของการอ้างอิงที่อ่อนแอจะเก็บไว้ในหน่วยความจำเพียงตราบเท่าที่การอ้างอิงสดอื่น ๆ ที่มีอยู่
dasblinkenlight

อาฉันเห็นสิ่งที่คุณหมายถึง นี่อาจเป็นกรณีที่หายากซึ่ง a destructorจะเป็นประโยชน์
Robert Harvey

1
ซับซ้อนเกินไป มันสามารถทำได้เช่น @weston คำตอบแทนที่เท่ากับและให้โรงงานเก็บชื่อ
Tulains Córdova

@ user1598390 สิ่งหนึ่งควรทำให้ง่ายที่สุดเท่าที่จะเป็นไปได้ แต่ไม่ง่ายกว่านี้ "การแก้ปัญหา" ของ Weston ไม่ได้ช่วยแก้ปัญหาของ OP (ไม่มีแผนที่) และการรวบรวมชื่อสร้างหน่วยความจำรั่วไหล (ใช่มีหน่วยความจำรั่วในจาวา)
dasblinkenlight

1

คุณควรกำหนดให้ constructors เป็นส่วนตัวและสร้างวิธีการเช่นgetNameInstance(String)ถ้ามีวัตถุที่มีชื่อเดียวกันอยู่แล้ว (ขึ้นอยู่กับ hastable ของคลาสที่คงที่) คุณส่งคืนการอ้างอิงนั้นมิฉะนั้นคุณจะสร้างวัตถุใหม่โดยใช้ constructor ส่วนตัวของคุณและเพิ่ม เพื่อ hashtable


คุณได้ทำซ้ำสิ่งที่ฉันพูดในวรรค 3 ของคำถาม ฉันตามหาทางเลือกอื่น
ถั่วลิสง

ฉันขอโทษฉันคิดว่าเราตอบเกือบจะในเวลาเดียวกันเพราะฉันตรวจสอบคำตอบก่อนโพสต์ของฉัน ที่จริงแล้วฉันพยายามตอบมันใน StackOverflown และมากกว่าที่มันถูกย้าย
HericDenis

1

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

class UniqueName
    {
        private string Name;
        public int ID;
        private static int Count=0;
        static List<UniqueName> lt=new List<UniqueName>();

        private UniqueName(string Name)
        {
            this.Name = Name;
            ID = ++Count;
        }

        public static UniqueName GetUniqueueInstance(string Name)
        {
            foreach (UniqueName un in lt)
            {
                if ( string.Compare( un.Name,Name,StringComparison.InvariantCultureIgnoreCase)==0)
                    return un;
            }

            UniqueName temp=new UniqueName(Name);
            lt.Add(temp);
            return temp;
        }
    }

นี่ไม่ใช่จาวาใช่ไหม คุณเขียนโค้ดหลอกหรือไม่? หรือในภาษาอื่น ๆ ? โปรดระบุอย่างชัดเจน
Rohit Jain

ดูเหมือน C # Akshay คุณควรเรียนรู้คอลเลกชันอื่น ๆ นอกเหนือListจาก Dictionary<string,UniqueName>นี้จะเป็นแบบที่ดีสำหรับ
weston
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.