การกระจายข้อมูลข้ามขอบเขตวัตถุ


10

หลายครั้งที่วัตถุธุรกิจของฉันมักจะมีสถานการณ์ที่ข้อมูลจำเป็นต้องข้ามขอบเขตวัตถุบ่อยเกินไป เมื่อทำ OO เราต้องการให้ข้อมูลอยู่ในวัตถุเดียวและมากที่สุดเท่าที่เป็นไปได้รหัสทั้งหมดที่เกี่ยวข้องกับข้อมูลนั้นควรอยู่ในวัตถุนั้น อย่างไรก็ตามกฎเกณฑ์ทางธุรกิจไม่ได้ปฏิบัติตามหลักการนี้ทำให้ฉันมีปัญหา

ตัวอย่างเช่นสมมติว่าเรามีคำสั่งซื้อที่มีหมายเลขของ OrderItems ซึ่งอ้างถึง InventoryItem ซึ่งมีราคา ฉันเรียกใช้ Order.GetTotal () ซึ่งสรุปผลของ OrderItem.GetPrice () ที่ทวีคูณปริมาณโดย InventoryItem.GetPrice () จนถึงตอนนี้ดีมาก

แต่จากนั้นเราพบว่าบางรายการมีการขายสองรายการต่อการจัดการหนึ่งรายการ เราสามารถจัดการสิ่งนี้ได้โดยให้ OrderItem.GetPrice () ทำบางอย่างเช่น InventoryItem.GetPrice (ปริมาณ) และปล่อยให้ InventoryItem จัดการกับสิ่งนี้

อย่างไรก็ตามเราพบว่าดีลแบบสองต่อหนึ่งนั้นมีระยะเวลาที่ จำกัด เท่านั้น ช่วงเวลานี้จะต้องเป็นไปตามวันที่สั่งซื้อ ตอนนี้เราเปลี่ยน OrderItem.GetPrice () เป็น InventoryItem.GetPrice (quatity, order.GetDate ())

แต่เราต้องสนับสนุนราคาที่แตกต่างกันขึ้นอยู่กับระยะเวลาที่ลูกค้าอยู่ในระบบ: InventoryItem.GetPrice (ปริมาณ, คำสั่งซื้อ GetDate (), คำสั่งซื้อ GetCustomer ())

แต่กลับกลายเป็นว่าข้อเสนอแบบสองต่อหนึ่งนั้นไม่ได้มีเพียงแค่การซื้อหลายรายการในสินค้าคงคลังเดียวกัน แต่ยังมีอีกหลายรายการสำหรับสินค้าใด ๆ ในประเภทสินค้าคงคลัง ณ จุดนี้เรายกมือขึ้นและให้รายการสั่งซื้อ InventoryItem และอนุญาตให้มันเดินทางผ่านกราฟอ้างอิงวัตถุผ่าน accessors เพื่อรับข้อมูลที่ต้องการ: InventoryItem.GetPrice (นี่)

TL; DR ฉันต้องการมีเพศสัมพันธ์ต่ำในวัตถุ แต่กฎเกณฑ์ทางธุรกิจมักจะบังคับให้ฉันเข้าถึงข้อมูลจากสถานที่ต่างๆเพื่อตัดสินใจโดยเฉพาะ

มีเทคนิคที่ดีในการจัดการกับเรื่องนี้หรือไม่? คนอื่นพบปัญหาเดียวกันหรือไม่


4
ดูเหมือนว่าคลาส InventoryItem พยายามทำมากเกินไปโดยการคำนวณราคาการส่งคืนราคาที่กำหนดเป็นสิ่งหนึ่ง แต่ราคาขายและกฎธุรกิจพิเศษไม่ควรอยู่ใน InventoryItem แผ่ออกชั้นเรียนสำหรับการคำนวณราคาของคุณและปล่อยให้มันจัดการกับความต้องการข้อมูลจากการสั่งซื้อสินค้าคงคลังและลูกค้าและอื่น ๆ
Chris

@ คริสใช่แยกตรรกะราคาอาจเป็นความคิดที่ดี ปัญหาของฉันคือวัตถุดังกล่าวจะถูกผนวกเข้ากับวัตถุที่เกี่ยวข้องกับลำดับทั้งหมดอย่างแน่นหนา ส่วนที่รบกวนฉันและส่วนที่ฉันสงสัยว่าฉันสามารถหลีกเลี่ยงได้
Winston Ewert

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

คำตอบ:


6

โดยพื้นฐานแล้วเรามีประสบการณ์แบบเดียวกับที่ฉันทำงานและเราได้จัดการโดยใช้คลาส OrderBusinessLogic เค้าโครงส่วนใหญ่ที่คุณได้อธิบายไว้นั้นได้ผลกับธุรกิจส่วนใหญ่ มันดีและสะอาดและเรียบง่าย แต่ในโอกาสที่คุณซื้อ 2 จากหมวดนี้เราถือว่าเป็น "การดำเนินธุรกิจ" และให้คลาส OrderBL คำนวณผลรวมใหม่โดยการสำรวจวัตถุที่ต้องการ

มันเป็นโซลูชั่นที่สมบูรณ์แบบไม่ เรายังมีชั้นเรียนหนึ่งที่รู้วิธีเกี่ยวกับชั้นเรียนอื่น ๆ มากเกินไป แต่อย่างน้อยเราก็ได้ย้ายสิ่งที่ต้องการออกจากวัตถุทางธุรกิจและไปสู่ชั้นตรรกะทางธุรกิจ


2
หากมีข้อสงสัยให้เพิ่มคลาสอื่น
Chris

1

เสียงเหมือนที่คุณจำเป็นต้องมีวัตถุที่แยกต่างหากส่วนลด (หรือรายการของพวกเขา) ที่ติดตามทุกสิ่งแล้วใช้ส่วนลด (s) เพื่อสั่งซื้อสิ่งที่ต้องการOrder.getTotal(Discount)หรือDiscount.applyTo(Order)หรือคล้ายกัน


ฉันสามารถดูที่วางรหัสในส่วนลดค่อนข้างแล้วในวัตถุสินค้าคงคลังจะดีกว่า แต่วัตถุลดราคาที่ดูเหมือนว่าจะยังคงต้องเข้าถึงข้อมูลจากวัตถุที่แตกต่างกันทั้งหมดเพื่อให้งานสำเร็จ อย่างน้อยที่สุดเท่าที่ฉันสามารถเห็นได้แก้ปัญหา
Winston Ewert

2
ฉันคิดว่าวัตถุส่วนลดเป็นความคิดที่ดี แต่ฉันจะทำให้มันใช้รูปแบบการสังเกตการณ์ ( en.wikipedia.org/wiki/Observer_pattern ) โดยมีส่วนลดเป็นหัวเรื่องของรูปแบบ
BlackICE

1

การเข้าใช้ข้อมูลจากคลาสอื่นนั้นไม่เป็นไร อย่างไรก็ตามคุณต้องการให้สิ่งนี้เป็นความสัมพันธ์แบบทิศทางเดียว ตัวอย่างเช่นสมมติว่า ClassOrder เข้าถึง CallItem ตามหลักการแล้ว ClassItem ไม่ควรเข้าถึง ClassOrder สิ่งที่ฉันคิดว่าคุณขาดหายไปในลำดับการสั่งซื้อของคุณคือตรรกะทางธุรกิจบางประเภทที่อาจหรือไม่อาจรับประกันคลาสเช่น Walter แนะนำ

แก้ไข: ตอบความคิดเห็นของ Winston

ฉันไม่คิดว่าคุณต้องการวัตถุสิ่งของสินค้าคงคลังเลย ... อย่างน้อยก็ในแบบที่คุณใช้อยู่ ฉันจะมีคลาสสินค้าคงคลังที่จัดการฐานข้อมูลสินค้าคงคลังแทน

ฉันจะอ้างถึงรายการสินค้าคงคลังด้วย ID คำสั่งซื้อแต่ละรายการจะมีรายการรหัสสินค้าคงคลังและปริมาณที่สอดคล้องกัน

จากนั้นฉันจะคำนวณยอดรวมของคำสั่งด้วยสิ่งนี้
Inventory.GetCost (รายการ, CUSTOMERNAME วัน)

จากนั้นคุณสามารถมีฟังก์ชันผู้ช่วยอื่น ๆ เช่น:

Inventory.ItemsLefts (int itemID)
Inventory.AddItem (int itemID, ปริมาณ int)
Inventory.RemoveItem (int itemID ปริมาณ int)
Inventory.AddBusinessRule (... )
Inventory.DeleteBusinessRule (... )


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

โดยพื้นฐานแล้วแนวคิดของคุณคือกำจัด OrderItem แทน Order ติดตามข้อมูลทั้งหมดนั้นเอง จากนั้นจึงง่ายต่อการส่งผ่านข้อมูลนั้นไปยังวัตถุอื่นสำหรับข้อมูลราคา ที่สามารถทำงานได้ (ในสถานการณ์พิเศษโดยเฉพาะอย่างยิ่งตัวอย่างนี้มีพื้นฐานมาจาก OrderItem ซับซ้อนเกินไปและจำเป็นต้องเป็นวัตถุของตัวเองจริงๆ)
Winston Ewert

สิ่งที่ไม่สมเหตุสมผลสำหรับฉันคือเหตุผลที่คุณต้องการให้มีการอ้างอิงคลังโฆษณาโดยใช้หมายเลข id แทนการอ้างอิงวัตถุ มันเป็นวิธีที่ดีกว่าสำหรับฉันในการติดตามการอ้างอิงวัตถุและปริมาณแล้วรหัสไอเท็มและการอ้างอิง
Winston Ewert

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

ฉันไม่แน่ใจว่าสิ่งที่คุณถามในความคิดเห็นที่สอง ไม่ใช่ทุกสิ่งที่จะต้องเป็นวัตถุ ฉันไม่แน่ใจจริงๆว่าคุณจะค้นหารายการเฉพาะได้อย่างไรโดยไม่มีรหัสบางประเภท
Pemdas

0

หลังจากคิดถึงเรื่องนี้มากขึ้นฉันก็คิดแผนทางเลือกของตัวเองขึ้นมา

กำหนดระดับราคา Inventory.GetPrice()ส่งคืนวัตถุราคา

Price OrderItem::GetPrice()
{
    return inventory.GetPrice().quantity(quantity);
}

Currency OrderItem::GetTotal()
{
    Price price = empty_price();
    for(item in order_items)
    {
         price = price.combine( item.GetPrice() )
    }
    price = price.date(date).customer(customer);
    return price.GetActualPrice();
}

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

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