ใครบ้างมีตัวอย่างเฉพาะของการใช้รูปแบบ Flyweight? [ปิด]


21

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

ตามคำจำกัดความมันบอกว่า:

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

ถ้าฉันอ่านถูกต้องพจนานุกรมและแฮชเทเบิลอาจเป็นกรณีของตุ้มน้ำหนักบินถูกต้องหรือไม่

ขอบคุณล่วงหน้า.


7
เรื่องเล็ก ๆ น้อย ๆ เกี่ยวกับ flyweights: ฉันเคยสร้างไฟล์ excel ขนาดใหญ่ (มากถึง 500k ระเบียนมากกว่า 100 คอลัมน์) ด้วย API ของบุคคลที่สาม สไตล์สำหรับเซลล์กลายเป็นความจำที่เข้มข้นมาก ดังนั้นเมื่อใดก็ตามที่ต้องการรูปแบบ hashtable จะถูกตรวจสอบว่ามีสไตล์ที่เท่ากันอยู่แล้วและให้ข้อมูลอ้างอิงถึงสไตล์นี้เท่านั้น การดัดแปลงนี้ทำให้การส่งออกเป็นไปได้ ตอนนี้การมีข้อมูลจำนวนมากใน excel เป็นความบ้าคลั่งในความคิดของฉัน แต่ตัวควบคุมมีมาโครวิเคราะห์ซึ่งพวกเขาต้องการเก็บไว้
Falcon

9
ความคิดเห็น: ฉันหวังว่าผู้ที่เขียนแบบและหนังสือและบทความ OO จะเข้าสู่โลกแห่งความเป็นจริงของโปรแกรมเมอร์โดยเฉลี่ยและหยุดใช้ภาษาอังกฤษแบบทนาย!
NoChance

1
"ฉันเคยสร้างไฟล์ excel ขนาดใหญ่ (มากถึง 500k ระเบียนมากกว่า 100 คอลัมน์)" - นั่นไม่มากเมื่อเทียบกับสิ่งที่ผู้ค้าบางรายสามารถสร้าง ;-)
quant_dev

หลังจากอ่านหลายตัวอย่างเหล่านี้ฉันคิดว่าในการบีบอัดข้อมูลหน่วยความจำจะเป็นสถานที่ที่ยอดเยี่ยมในการใช้เทคนิคนี้ ขอบคุณสำหรับความช่วยเหลือ!
Jeremy E

เซลล์ตารางใน GWT คือ flyweights
user16764

คำตอบ:


19

ตัวอย่างหนึ่งอยู่ในไลบรารี Java Java มีประเภทดั้งเดิม (เช่นintซึ่งเป็นจำนวนเต็ม 32 บิต) และ wrappers สำหรับพวกเขา (เช่นIntegerที่ wraps int) มีวิธีการที่จะ "กล่อง" ให้บริการintเป็นIntegerunbox และเป็นInteger intเครื่องห่อมีความจำเป็นเพราะประเภทดั้งเดิมไม่ใช่วัตถุดังนั้นจึงไม่สามารถใช้เป็นกุญแจในMaps หรือวางในCollections ได้

วิธีการชกมวยใช้อาร์เรย์ของวัตถุฟลายเวทเป็นประเภทแคชสำหรับIntegers ที่สอดคล้องกับintค่าระหว่าง -128 ถึง 127 เนื่องจากสิ่งเหล่านี้เป็นค่าที่น่าจะใช้เป็นกุญแจหรือวางไว้ในคอลเลกชันจึงช่วยลดการจัดสรรและการใช้หน่วยความจำ (หากมี 5000000 Integers แสดงถึงค่า 0 ที่ลอยอยู่นั้นจะใช้หน่วยความจำมากถึง 5000000 เท่าของการใช้อินสแตนซ์ flyweight อีกครั้ง)



1
ดังนั้นพูลฝึกงานสำหรับสตริงใน C # จึงเป็นอีกตัวอย่างหนึ่งของรูปแบบฟลายเวทที่ถูกต้อง?
Jeremy E

1
@ Jeremy E: ใช่ในความคิดของฉันคุณสามารถเรียก string เพื่อใช้งานแอพพลิเคชั่นของรูปแบบ flyweight ซึ่งเหมาะสำหรับสตริงไม่เพียง แต่เกี่ยวกับการใช้หน่วยความจำ แต่ยังเกี่ยวกับประสิทธิภาพของรันไทม์
เหยี่ยว

ตัวชี้ที่ติดแท็กด้วย Objective-C นำสิ่งนี้ไปสุดขั้ว เลขจำนวนเต็มชนิดบรรจุกล่องมากถึง 56 บิตและสตริงจำนวนมากถึงหกตัวอักษรไม่ได้ถูกจัดสรรเป็นวัตถุ แต่ข้อมูลทั้งหมดจะถูกบรรจุลงในตัวชี้วัตถุ
gnasher729

9

กราฟิก โดยทั่วไปแล้วภาพแรสเตอร์ (ซึ่งเป็นกระดูกสันหลังของคอมพิวเตอร์กราฟิกระดับผู้บริโภคส่วนใหญ่) เป็นซีพียูราคาถูก แต่หน่วยความจำราคาแพงใช้งานได้ (ซึ่งใช้ได้เพราะหน่วยความจำราคาถูก แต่ซีพียูมีราคาแพง) หากภาพแรสเตอร์นั้นซ้ำหลายครั้งในการแสดงผล UI ที่มีขนาดใหญ่ขึ้น (จากไอคอนในแอพ Windows GUI ไปยังตัวอักษรของตัวอักษรในโปรแกรมประมวลผลคำไปจนถึงพื้นผิวบนพื้นผิวในเกม 3 มิติ) โหลดภาพลงในหน่วยความจำเพียงครั้งเดียวและชี้ไปที่มันโดยใช้วัตถุง่าย ๆ ที่มีราคาถูกในการทำและไม่ต้องใช้หน่วยความจำจำนวนมาก สไปรท์ซึ่งเป็นเพียงจุดในพื้นที่กราฟิกที่ภาพควรจะแสดงเป็นเพียงจุด 3D และตัวชี้หน่วยความจำไปที่พิกเซลแรกของภาพที่จะใช้ อาจรวมถึงขนาดของส่วนของไฟล์ภาพสไปรต์ที่จะใช้ ทั้งในแง่กราฟิกหรือหน่วยความจำ ข้อมูลนี้มีราคาไม่แพงมากในการเปลี่ยนพูดเปลี่ยนภาพหรือที่ตั้งของสไปรต์และสามารถทำได้โดยไม่ต้องโหลดภาพใหม่ทุกครั้งจึงเพิ่มประสิทธิภาพการทำงานของโปรแกรมพื้นฐานอย่างมากเพื่อจัดการและแสดงส่วนที่เหมาะสมของ ภาพที่เหมาะสมเพื่อแสดง UI "ฉาก" ที่สมบูรณ์


3

Characterอินสแตนซ์ของช่วง ASCII ใน Smalltalk คือ flyweights

เมื่อคุณประเมินสิ่งที่ชอบCharacter space, Character class >> #value:รัน:

value: anInteger 
    "Answer the Character whose value is anInteger."

    anInteger > 255 ifTrue: [^self basicNew setValue: anInteger].
    ^ CharacterTable at: anInteger + 1.

ตัวแปรคลาสCharacterTableถูกกำหนดค่าเริ่มต้นเช่นนี้:

initialize
    "Create the table of unique Characters, and DigitsValues."
    "Character initializeClassificationTable"

    CharacterTable ifNil: [
        "Initialize only once to ensure that byte characters are unique"
        CharacterTable := Array new: 256.
        1 to: 256 do: [:i | CharacterTable
            at: i
            put: (self basicNew setValue: i - 1)]].
    self initializeDigitValues

ดังนั้นเมื่อคุณสร้าง String ช่วง ASCII CharacterจะมาจากCharacterTableแทนที่จะสร้างขึ้นใหม่ทุกครั้ง


3

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

  • สถานะที่แท้จริง:ถูกเก็บไว้ในฟลายเวท; ประกอบด้วยข้อมูลที่เป็นอิสระในบริบท flyweights จึงทำให้สามารถแบ่งปันได้
  • สถานะ Extrinsic:ขึ้นอยู่กับและแตกต่างกันไปตามบริบทของฟลายเวทและไม่สามารถแบ่งปันได้ วัตถุไคลเอนต์มีหน้าที่รับผิดชอบในการผ่านสถานะภายนอกไปยังฟลายเวทเมื่อมันต้องการ

สมมติว่าเราต้องการพัฒนาแอปพลิเคชั่นตัวแก้ไขข้อความอย่างง่ายโดยที่แต่ละคอลัมน์มีแถวทั้งหมดของข้อความและแถวสามารถมีอักขระได้

ขึ้นเขียงที่นี่เป็นวิธีการออกแบบคลาสตัวละคร char cภายในชั้นเรียนตัวอักษรที่ควรจะเป็นหลัก (รัฐที่แท้จริง) วัตถุ อย่างไรก็ตามถ่านสามารถมีแบบอักษรและขนาด (สถานะภายนอก); ดังนั้นเราจำเป็นต้องเก็บสถานะภายนอกของมันไว้ในแถว (ไคลเอนต์) และเข้าถึงเมื่อจำเป็น เพื่อจุดประสงค์นี้สองรายการที่เก็บแบบอักษรและขนาดจะถูกสร้างขึ้น

ด้วยการทำตามรูปแบบ Flyweight ตอนนี้ตัวละครจะสามารถนำมาใช้ซ้ำได้และวัตถุจะถูกอ้างอิงจากรายการของวัตถุที่เฉพาะเจาะจง (พูลฟลายเวท) ซึ่งมีสัญลักษณ์ ASCII ทั้งหมด ( Characterวัตถุ)

นี่คือสิ่งที่ฉันอธิบายด้วยภาพ:

ป้อนคำอธิบายรูปภาพที่นี่

สำหรับการพิมพ์ 'hello' ต้องการเพียง 4 Characterวัตถุแทน 5 เมื่อเปลี่ยนแบบอักษรแล้วไม่จำเป็นต้องมีวัตถุใหม่ โปรดทราบว่าสิ่งนี้จะเป็นไปไม่ได้หากเราเก็บสถานะภายนอกไว้ในคลาสอักขระเช่น

class Character
{
    char c;
    int Size;
    Font font;

    ....
}

การใช้รูปแบบนี้กับชุดข้อมูลขนาดใหญ่จะนำไปสู่การปรับให้เหมาะสมอย่างมีนัยสำคัญกับความซับซ้อนของหน่วยความจำของแอปพลิเคชันและการใช้งานวัตถุ

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