การห่อหุ้มนั้นมีจุดประสงค์ แต่สามารถนำไปใช้ในทางที่ผิดหรือใช้ในทางที่ผิด
พิจารณาบางอย่างเช่น Android API ซึ่งมีคลาสที่มีฟิลด์เป็นสิบ (หากไม่ใช่หลายร้อย) การเปิดเผยเขตข้อมูลเหล่านั้นทำให้ผู้บริโภคของ API ทำให้การนำทางและใช้งานยากขึ้นนอกจากนี้ยังทำให้ผู้ใช้เข้าใจผิดว่าเขาสามารถทำสิ่งที่เขาต้องการกับเขตข้อมูลเหล่านั้นซึ่งอาจขัดแย้งกับวิธีการใช้งาน ดังนั้นการห่อหุ้มจึงยอดเยี่ยมในแง่ของการบำรุงรักษาการใช้งานการอ่านและการหลีกเลี่ยงข้อบกพร่องที่บ้าคลั่ง
ในทางกลับกัน POD หรือชนิดข้อมูลเก่าแบบเดิมเช่นโครงสร้างจาก C / C ++ ซึ่งเขตข้อมูลทั้งหมดเป็นสาธารณะจะมีประโยชน์เช่นกัน การมีผู้ได้รับ / ผู้ตั้งค่าที่ไร้ประโยชน์เช่นเดียวกับที่สร้างโดยคำอธิบายประกอบ @data ในลอมบอกเป็นเพียงวิธีในการรักษา "รูปแบบการห่อหุ้ม" หนึ่งในไม่กี่เหตุผลที่เราทำ "ไร้ประโยชน์" getters / setters ใน Java เป็นว่าวิธีการที่ให้สัญญา
ใน Java คุณไม่สามารถมีฟิลด์ในอินเทอร์เฟซได้ดังนั้นคุณใช้ getters และ setters เพื่อระบุคุณสมบัติทั่วไปที่ implementers ทั้งหมดของอินเตอร์เฟสนั้นมี ในภาษาล่าสุดเช่น Kotlin หรือ C # เราเห็นแนวคิดของคุณสมบัติเป็นเขตข้อมูลที่คุณสามารถประกาศตัวตั้งค่าและตัวรับ ในท้ายที่สุดตัวรับสัญญาณ / ตัวเซ็ตที่ไร้ประโยชน์เป็นมรดกตกทอดมากกว่าที่ Java มีอยู่เว้นแต่ว่า Oracle จะเพิ่มคุณสมบัติเข้าไป ตัวอย่างเช่น Kotlin ซึ่งเป็นภาษา JVM อื่นที่พัฒนาโดย JetBrains มีคลาสข้อมูลซึ่งโดยทั่วไปแล้วจะทำในสิ่งที่หมายเหตุประกอบ @data ทำในลอมบอก
นี่คือตัวอย่างบางส่วน:
class DataClass
{
private int data;
public int getData() { return data; }
public void setData(int data) { this.data = data; }
}
นี่เป็นกรณีของการห่อหุ้มที่ไม่ดี ทะเยอทะยานและตัวตั้งค่านั้นไร้ประโยชน์ การห่อหุ้มส่วนใหญ่จะใช้เพราะนี่คือมาตรฐานในภาษาเช่น Java ไม่ได้ช่วยได้จริงนอกจากการรักษาความสอดคล้องของรหัสฐาน
class DataClass implements IDataInterface
{
private int data;
@Override public int getData() { return data; }
@Override public void setData(int data) { this.data = data; }
}
นี่เป็นตัวอย่างที่ดีของการห่อหุ้ม การห่อหุ้มจะใช้ในการบังคับใช้สัญญาในกรณีนี้ IDataInterface วัตถุประสงค์ของการห่อหุ้มในตัวอย่างนี้คือการทำให้ผู้บริโภคของคลาสนี้ใช้วิธีการที่ให้ไว้โดยส่วนต่อประสาน แม้ว่าตัว getter และ setter จะไม่ทำอะไรที่เป็นแฟนซี แต่ตอนนี้เราได้กำหนดลักษณะทั่วไประหว่าง DataClass และตัวดำเนินการอื่น ๆ ของ IDataInterface ดังนั้นฉันสามารถมีวิธีเช่นนี้
void doSomethingWithData(IDataInterface data) { data.setData(...); }
ตอนนี้เมื่อพูดถึงการห่อหุ้มฉันคิดว่ามันสำคัญที่จะต้องแก้ปัญหาไวยากรณ์ด้วย ฉันมักจะเห็นคนบ่นเกี่ยวกับไวยากรณ์ที่จำเป็นในการบังคับใช้การห่อหุ้มมากกว่าการห่อหุ้มตัวเอง ตัวอย่างหนึ่งที่นึกถึงมาจาก Casey Muratori (คุณสามารถเห็นคำพูดของเขาที่นี่ )
สมมติว่าคุณมีคลาสผู้เล่นที่ใช้การห่อหุ้มและต้องการย้ายตำแหน่งของเขา 1 หน่วย รหัสจะมีลักษณะเช่นนี้:
player.setPosX(player.getPosX() + 1);
มันจะมีลักษณะเช่นนี้:
player.posX++;
ที่นี่เขาให้เหตุผลว่า encapsulations นำไปสู่การพิมพ์ที่มากขึ้นโดยไม่มีผลประโยชน์เพิ่มเติมและในหลายกรณีสามารถเป็นจริง แต่สังเกตเห็นบางสิ่งบางอย่าง อาร์กิวเมนต์ขัดแย้งกับไวยากรณ์ไม่ใช่การห่อหุ้มตัวเอง แม้ในภาษาอย่าง C ที่ขาดแนวคิดเรื่องการห่อหุ้มคุณก็มักจะเห็นตัวแปรใน structs prexifed หรือ sufixed ด้วย '_' หรือ 'my' หรืออะไรก็ตามที่บ่งบอกว่าพวกเขาไม่ควรใช้ผู้บริโภคของ API ราวกับว่าพวกเขาเป็น เอกชน.
ความจริงของเรื่องนี้คือการห่อหุ้มสามารถช่วยทำให้รหัสสามารถบำรุงรักษาได้ง่ายขึ้นและใช้งานง่ายขึ้น พิจารณาคลาสนี้:
class VerticalList implements ...
{
private int posX;
private int posY;
... //other members
public void setPosition(int posX, int posY)
{
//change position and move all the objects in the list as well
}
}
หากตัวแปรเป็นแบบสาธารณะในตัวอย่างนี้ผู้บริโภคของ API นี้จะสับสนว่าเมื่อใดที่จะใช้ posX และ posY และเมื่อใดควรใช้ setPosition () ด้วยการซ่อนรายละเอียดเหล่านั้นคุณจะช่วยให้ผู้บริโภคใช้ API ของคุณได้ง่ายขึ้น
ไวยากรณ์เป็นข้อ จำกัด ในหลายภาษาแม้ว่า อย่างไรก็ตามภาษาที่ใหม่กว่านำเสนอคุณสมบัติซึ่งทำให้เรามีไวยากรณ์ที่ดีของสมาชิก publice และประโยชน์ของการห่อหุ้ม คุณจะพบคุณสมบัติใน C #, Kotlin แม้ใน C ++ หากคุณใช้ MSVC นี่คือตัวอย่างใน Kotlin
คลาส VerticalList: ... {var posX: Int set (x) {field = x; ... } var posY: Int set (y) {field = y; ... }}
ที่นี่เราประสบความสำเร็จเช่นเดียวกับในตัวอย่าง Java แต่เราสามารถใช้ posX และ posY ราวกับว่าพวกเขาเป็นตัวแปรสาธารณะ เมื่อฉันพยายามที่จะเปลี่ยนค่าของพวกเขาแม้ว่าร่างกายของชุดตัวตั้งค่า () จะถูกดำเนินการ
ใน Kotlin สิ่งนี้จะเทียบเท่ากับ Java Bean ที่มี getters, setters, hashcode, เท่ากับและ toString ที่นำมาใช้:
data class DataClass(var data: Int)
ขอให้สังเกตว่าไวยากรณ์นี้ช่วยให้เราสามารถ Java Bean ในหนึ่งบรรทัด คุณสังเกตเห็นปัญหาที่ภาษาเช่น Java มีอย่างถูกต้องในการใช้การห่อหุ้ม แต่นั่นเป็นความผิดของ Java ที่ไม่ได้ห่อหุ้มตัวเอง
คุณบอกว่าคุณใช้ @Data ของลอมบอกเพื่อสร้างผู้ได้รับและผู้ตั้งค่า สังเกตชื่อ @Data ส่วนใหญ่จะใช้กับคลาสของข้อมูลที่เก็บข้อมูลเท่านั้นและมีไว้เพื่อให้เป็นอนุกรมและไม่ถูกจัดลำดับ คิดถึงบางอย่างเช่นไฟล์บันทึกจากเกม แต่ในสถานการณ์อื่น ๆ เช่นเดียวกับองค์ประกอบ UI คุณต้องการ setters แน่นอนเพราะเพียงแค่การเปลี่ยนค่าของตัวแปรอาจไม่เพียงพอที่จะได้รับพฤติกรรมที่คาดหวัง
"It will create getters, setters and setting constructors for all private fields."
- วิธีที่คุณอธิบายเครื่องมือนี้ดูเหมือนว่าจะยังคงมีการห่อหุ้ม (อย่างน้อยก็ในแบบหลวม ๆ แบบอัตโนมัติและแบบจำลองโลหิตจาง) ดังนั้นปัญหาคืออะไร