การใช้วัตถุทางธุรกิจในรูปแบบการดู


11

เมื่อใช้ออบเจ็กต์ธุรกิจที่ใช้ซ้ำได้สิ่งที่ควรคำนึงถึงเป็นแนวปฏิบัติที่ดีที่สุดเมื่อสร้างมุมมองแบบจำลอง

เราใช้วัตถุที่เราเรียกใช้Builderเพื่อสร้างแบบจำลองมุมมองของเรา ตัวสร้างหนึ่งสำหรับแต่ละหน่วยของมุมมองแบบลอจิคัล (คำสั่งผู้ใช้ ฯลฯ ) ซึ่งแต่ละหน่วยสามารถมีรูปแบบมุมมองที่แตกต่างกันจำนวนหนึ่ง (คำสั่งซื้อประกอบด้วยข้อมูลสรุปบรรทัดคำสั่งและอื่น ๆ )

ผู้สร้างอาจดึงข้อมูลผ่านวัตถุทางธุรกิจมาตรฐานหนึ่งรายการขึ้นไปเพื่อสร้างแบบจำลองมุมมอง

อะไรคือการปฏิบัติที่ดีขึ้นเมื่อพูดถึงการใช้อ็อบเจกต์ธุรกิจ / โมเดลในโมเดลที่มีมุมมอง?

วิธีที่ 1

อนุญาตให้ใช้วัตถุธุรกิจในโมเดลมุมมองหรือไม่

//Business object in some library
public class Order
{
    public int OrderNum;
    public int NumOrderLines;
    //...
}

//Order builder in website
public class OrderBuilder
{
    public OrderSummary BuildSummaryForOrder(int OrderNum)
    {
        Some.Business.Logic.Order obOrder = Some.Business.Logic.GetOrder(OrderNum);
        //Any exception handling, additional logic, or whatever

        OrderSummary obModel = new OrderSummary();
        obModel.Order = obOrder;

        return obModel;
    }
}

//View model
public class OrderSummary
{
    public Some.Business.Logic.Order Order;
    //Other methods for additional logic based on the order
    //and other properties
}

วิธีที่ 2

รับข้อมูลที่จำเป็นจากวัตถุทางธุรกิจเท่านั้น

//Business object in some library
public class Order
{
    public int OrderNum;
    public int NumOrderLines;
    //...
}

//Order builder in website
public class OrderBuilder
{
    public OrderSummary BuildSummaryForOrder(int OrderNum)
    {
        Some.Business.Logic.Order obOrder = Some.Business.Logic.GetOrder(OrderNum);
        //Any exception handling, additional logic, or whatever

        OrderSummary obModel = new OrderSummary()
        {
            OrderNum = obOrder.OrderNum,
            NumOrderLnes = obOrder.NumOrderLines,
        }

        return obModel;
    }
}

//View model
public class OrderSummary
{
    public int OrderNum;
    public int NumOrderLines
    //Other methods for additional logic based on the order
    //and other properties
}

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

คำตอบ:


12

ตัวเลือกที่ 1 สร้างการมีเพศสัมพันธ์อย่างแน่นหนาระหว่างโมเดลโดเมนและมุมมอง สิ่งนี้ตรงกันข้ามกับมุมมองที่เป็นปัญหามากซึ่งออกแบบมาเพื่อแก้ไข

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

ฉันมักจะสนับสนุนวิธีการที่ 2 มักจะเป็นกรณีที่มุมมองแบบจำลองอาจดูคล้ายกันมากแม้จะเหมือนกับวัตถุแบบจำลองโดเมน แต่ความแตกต่างที่ฉันกล่าวถึงคือเหตุผลที่แตกต่างกันสำหรับการเปลี่ยนแปลง


ฉันถูกต้องในการคิดว่าโดย "เหตุผลในการเปลี่ยนแปลง" คุณหมายถึงการเปลี่ยนแปลงในแง่ของการบำรุงรักษาไม่ใช่การเปลี่ยนแปลงในการปรับปรุง (เช่นเหตุการณ์ UI)
Andy Hunt

@AndyBursh ใช่แล้ว - ดูบทความนี้โดยเฉพาะอย่างยิ่งบรรทัด"Robert C. Martin กำหนดความรับผิดชอบเป็นเหตุผลในการเปลี่ยนแปลงและสรุปว่าชั้นเรียนหรือโมดูลควรมีหนึ่งและเหตุผลเดียวเท่านั้นที่จะเปลี่ยน"
MattDavey

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

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

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

2

ตัวเลือกที่ 1 เป็นที่นิยมมากกว่าเพราะหลีกเลี่ยงการทำสำเนารหัส แค่นั้นแหละ.

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

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


YAGNI นักฆ่าลับในการแก้ปัญหาการออกแบบซอฟต์แวร์ส่วนใหญ่
Martin Blore

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

"หากรูปแบบโดเมนมีการเปลี่ยนแปลงอย่างมีนัยสำคัญเกือบจะแน่นอนว่ามุมมองจะต้องเปลี่ยนแปลงอยู่ดี" - เห็นด้วย แต่เมื่อคุณมีการเปลี่ยนแปลงเล็กน้อยในโดเมน? ด้วยตัวเลือกที่หนึ่งการเปลี่ยนแปลงทุกอย่างในโดเมน (แม้เพียงแค่การเปลี่ยนชื่อคุณสมบัติ) จะต้องมีการเปลี่ยนแปลงที่สอดคล้องกับมุมมอง นี่คือพิษแน่นอนสำหรับการบำรุงรักษา
MattDavey

@MattDavey: ถ้าคุณเปลี่ยนชื่อคุณสมบัติแล้วด้วยโมเดลมุมมองที่แยกต่างหากคุณต้องเปลี่ยนมุมมองด้วย (หรือแผนที่ใด ๆ ระหว่างโดเมนและโมเดลมุมมอง) และตอนนี้มีสองชื่อที่แตกต่างกันสำหรับสิ่งเดียวกันซึ่งแน่นอนว่าจะทำให้เกิดความสับสน
Michael Borgwardt

@ Lucifer Sam: เห็นได้ชัดว่าเรามีแนวคิดที่แตกต่างกันมากว่าแบบจำลองมุมมองคืออะไร คุณฟังดูแปลกมากสำหรับฉันเช่นคุณกำลังอธิบายแอพเมนเฟรมสำหรับเทอร์มินัลที่โง่เง่า แต่แน่นอนว่าไม่ใช่แอปเว็บที่ทันสมัยหรือแอปไคลเอนต์ที่มีไขมัน
Michael Borgwardt

2

หลักการและมนต์บางครั้งก็มีค่าสำหรับแนวทางการออกแบบ ... แต่นี่คือคำตอบที่ปฏิบัติของฉัน:

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

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

ตามแนวคิดแล้วโมเดลการดูของคุณควรประกอบด้วยสตริงที่มีการจัดรูปแบบไว้ล่วงหน้าเกือบทั้งหมด คิดเกี่ยวกับมัน ... คุณไม่ต้องการแม้แต่ DateTime หรือทศนิยมในโมเดลมุมมองของคุณเพราะคุณติดตรรกะในการจัดรูปแบบใน C #, Javascript, Objective-C เป็นต้น


2
ฉันไม่เคยมีปัญหาใด ๆ กับการจำลองโดเมนแบบอนุกรม และแปลงทุกอย่างเป็นสายอักขระในโมเดลหรือไม่? อย่างจริงจัง?
Michael Borgwardt

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

ขออภัย แต่นั่นเป็นคำแนะนำที่น่ากลัวสำหรับแอปพลิเคชันใด ๆ มันนำไปสู่แอปพลิเคชันที่ overengineered เต็มไปด้วยรหัสที่ซ้ำกันซึ่งตรงกันข้ามกับความยืดหยุ่นที่แน่นอน
Michael Borgwardt

1
@MichaelBorgwardt ดูเหมือนว่าคุณคุ้นเคยกับการทำงานกับโมเดลโดเมนโลหิตจางที่มีเอนทิตี้น้อยกว่าถุงคุณสมบัติที่มีพฤติกรรมน้อยหรือไม่มีเลย ในกรณีนั้นใช่ DTO / View-model โดยทั่วไปจะซ้ำกัน อย่างไรก็ตามถ้าคุณมีโมเดลโดเมนที่มีความสัมพันธ์ที่ซับซ้อนเลเยอร์ของ DTOs / View-models จำเป็นและพวกมันจะไม่คล้ายกับเอนทิตีของโดเมน
MattDavey

@MattDavey: ดูเหมือนว่ารูปแบบโดเมนที่คุณคุ้นเคยกับการทำงานไม่เพียง แต่เป็นคนฉลาดแกมโกง ฉันไม่ชอบแบบจำลองโลหิตจาง แต่พวกเขายังคงเป็นแบบจำลองและพฤติกรรมของพวกเขาควรถูก จำกัด ให้แสดงถึงโดเมน หลักการเดียวรับผิดชอบและทุกสิ่งที่ ...
ไมเคิล Borgwardt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.