รูปแบบการคัดลอกคลาส?


11

ฉันกำลังทำงานเป็นนักพัฒนาเดี่ยวในโครงการปัจจุบันของฉัน ฉันสืบทอดโครงการจากผู้พัฒนารายอื่นซึ่งออกจาก บริษัท ไปแล้ว มันเป็นเว็บแอพพลิเคชั่นรูปแบบมุมมอง - คอนโทรลเลอร์ใน C # มันใช้ Entity Framework สำหรับการทำแผนที่วัตถุสัมพันธ์ และมีคลาสที่แตกต่างกันสองชุดสำหรับประเภทในรูปแบบโดเมน ชุดหนึ่งใช้สำหรับการโต้ตอบกับ ORM และอีกชุดหนึ่งใช้เป็นแบบจำลองในระบบ MVC ตัวอย่างเช่นอาจมีสองคลาสดังนี้:

public class Order{
    int ID{get;set;}
    String Customer{get;set;}
    DateTime DeliveryDate{get;set;}
    String Description{get;set;}
}

และ

public class OrderModel{
    String Customer{get;set;}
    DateTime DeliveryDate{get;set;}
    String Description{get;set;}
    public OrderModel( Order from){
        this.Customer= from.Customer;
        // copy all the properties over individually
    }
    public Order ToOrder(){
        Order result =new Order();
        result.Customer = this.Customer;
        // copy all the properties over individually
    }

}

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

UPDATE

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

public class EditOrderPagelModel
{
    public OrderModel Order{get;set;}
    public DateTime EarliestDeliveryDate{get;set;}
    public DateTime LatestAllowedDeliveryDate{get;set;}
}

ฉันเห็นประโยชน์ของกลุ่มที่สามนี้อย่างชัดเจนและไม่มีแผนที่จะรวมเข้ากับสิ่งอื่น (แม้ว่าฉันจะเปลี่ยนชื่อ)

ขณะนี้คลาสในกลุ่มโมเดลยังใช้โดย API ของแอปพลิเคชันซึ่งฉันยังสนใจที่จะรับฟังว่าเป็นความคิดที่ดีหรือไม่

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


1
"ฉันสืบทอดโครงการจากผู้พัฒนารายอื่นซึ่งออกจาก บริษัท ไปแล้ว" มีเว็บไซต์ที่ทุ่มเทให้กับเรื่องราวที่เริ่มต้นด้วยวิธีนี้

เกี่ยวกับการอัปเดตของคุณ: ดูเหมือนว่าจะเป็นทางอ้อมมากเกินไปเพื่อผลประโยชน์ที่ไม่เพียงพอ
Robert Harvey

@RobertHarvey คุณหมายถึงอะไรที่เป็นคนอ้อมมากเกินไป?
Robert Ricketts

1
OrderModel OrderViewModel (สิ่งที่คุณอาจอ้างถึงว่าเป็น EditOrderPageModel) นั้นมีทิศทางที่เพียงพอ ดูคำตอบของฉันด้านล่าง
Robert Harvey

@RobertHarvey นี่ฟังดูเหมือนคำตอบของคำถามที่ฉันพยายามถามจริงๆ
Robert Ricketts

คำตอบ:


16

ดังนั้นฉันจึงพลาดสิ่งสำคัญที่นี่

ใช่

ในขณะที่สิ่งเหล่านี้มีลักษณะเหมือนกันและเป็นตัวแทนของสิ่งเดียวกันในโดเมนพวกเขาไม่ใช่วัตถุ (OOP) เดียวกัน

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

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

โดยการผูกเอนทิตีของคุณเข้ากับกรอบทั้งสองคุณทำให้แย่ลงกว่าเดิมมาก


7

วัตถุประสงค์ของ View Model คือเพื่อให้ decoupling ได้สองวิธี: โดยการให้ข้อมูลในรูปแบบที่ View ต้องการ (เป็นอิสระจากโมเดล) และ (โดยเฉพาะใน MVVM) โดยการผลักดันตรรกะ View บางส่วนหรือทั้งหมดจากมุมมอง เพื่อดูรูปแบบ

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

ในทางกลับกัน View View อาจจะให้ความสนใจNameกับลูกค้ามากกว่า ID ไม่ใช่ ไม่จำเป็นต้องมี ID เว้นแต่ว่าลูกค้ากำลังได้รับการอัพเดตในรุ่น

นอกจากนี้ View Model สามารถและมักจะมีรูปร่างที่แตกต่าง (ยกเว้นว่ามันเป็นCRUDบริสุทธิ์) วัตถุรูปแบบมุมมองใบแจ้งหนี้อาจมีชื่อลูกค้าที่อยู่และรายการโฆษณา แต่รุ่นนั้นมีลูกค้าและรายละเอียด

กล่าวอีกนัยหนึ่งโดยปกติแล้วใบแจ้งหนี้จะไม่ถูกจัดเก็บในลักษณะเดียวกับที่แสดง


3

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

ในการทำให้เรื่องสั้นสั้น - นี่คือเหตุผลหลักที่คุณต้องการ:

1) Encapsulation - ข้อมูลซ่อนแอปพลิเคชันของคุณ

2)โมเดลขนาดเล็กนั้นรวดเร็วในการทำให้เป็นอันดับและง่ายต่อการส่ง

3)พวกเขาให้บริการวัตถุประสงค์ที่แตกต่างกันแม้ว่าจะทับซ้อนกันและดังนั้นจึงควรมีวัตถุที่แตกต่างกัน

4)บางครั้งก็ทำให้รู้สึกมีสำหรับแบบสอบถามที่แตกต่างกันที่แตกต่างกันมูลค่าวัตถุ ฉันไม่รู้ว่ามันเป็นอย่างไรใน C # แต่ใน Java เป็นไปได้ที่จะใช้POJOเพื่อรวบรวมผลลัพธ์ ถ้าฉันต้องการซิงเกิ้ลเดียวorderฉันก็ใช้คำสั่ง -Entity แต่ถ้าฉันต้องการเพียงคอลัมน์บางคอลัมน์ที่เต็มไปด้วยจำนวนข้อมูลการใช้ออบเจกต์ขนาดเล็กนั้นมีประสิทธิภาพมากกว่า


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

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

0

(ข้อจำกัดความรับผิดชอบ: ฉันเห็นว่ามีการใช้วิธีนี้เท่านั้นฉันอาจเข้าใจวัตถุประสงค์ที่แท้จริงของการทำเช่นนั้น

นี่เป็นอีกหนึ่งบิตขาดหายไป: แปลงระหว่างและOrderOrderModel

Orderชั้นจะเชื่อมโยงกับการออมของคุณในขณะที่OrderModelจะเชื่อมโยงกับการออกแบบของดูรุ่นของคุณ

โดยทั่วไปแล้วทั้งสองวิธีจะให้ "ในทางเวทย์มนตร์" (บางครั้งเรียกว่า DI, IoC, MVVM หรืออีกสิ่งหนึ่ง) นั่นคือแทนที่จะใช้วิธีการแปลงทั้งสองนี้เป็นส่วนหนึ่งของOrderModelพวกเขาแทนที่จะเป็นของชั้นเรียนที่อุทิศตนเพื่อการแปลงระหว่างสิ่งเหล่านี้ คลาสนั้นจะถูกลงทะเบียนกับเฟรมเวิร์กเพื่อให้เฟรมเวิร์กสามารถค้นหาได้อย่างง่ายดาย

public class OrderModel {
    ...
    public OrderModel(Order from) { ... }
    public Order ToOrder() { ... }
}

เหตุผลในการทำเช่นนี้คือเมื่อใดก็ตามที่มีการข้ามจากOrderModelไปยังOrderหรือกลับกันคุณรู้ว่าข้อมูลบางอย่างต้องถูกโหลดจากหรือบันทึกลงใน ORM


หากฉันรักษาทั้งสองไว้ฉันอยากจะตั้งพวกเขาให้มีการแปลงโดยอัตโนมัติมากขึ้น
Robert Ricketts

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