เหตุใดจึงต้องแยกชั้นเรียน CommandHandler พร้อมหมายเลขอ้างอิง () แทนวิธีการจัดการใน Command เอง


13

ฉันมีส่วนหนึ่งของรูปแบบ CQRS ที่นำมาใช้โดยใช้สถาปัตยกรรม S # arpดังนี้:

public class MyCommand
{
    public CustomerId { get; set; }

    // some other fields
}

public class MyCommandHandler<MyCommand> : ICommandHandler<MyCommand, CommandResult>
{
    Handle(MyCommand command)
    {
        // some code for saving Customer entity

        return CommandResult.Success;
    }
}

ฉันสงสัยว่าทำไมไม่เพียงแค่มีคลาสCommandที่มีทั้งข้อมูลและวิธีการจัดการ? มันเป็นข้อดีของการทดสอบที่คุณต้องทดสอบตรรกะการจัดการคำสั่งแยกต่างหากจากคุณสมบัติคำสั่งหรือไม่? หรือมันเป็นบางอย่างที่ต้องการทางธุรกิจบ่อยครั้งที่คุณจำเป็นต้องมีคำสั่งอย่างใดอย่างหนึ่งจัดการโดยการใช้งานที่แตกต่างกันของICommandHandler<MyCommand, CommandResult>?


ฉันมีคำถามเดียวกันน่าดู: blogs.cuttingedge.it/steven/posts/2011/…
rdhaundiyal

คำตอบ:


14

ขำ ๆ คำถามนี้ทำให้ฉันนึกถึงบทสนทนาเดียวกับที่ฉันมีกับหนึ่งในวิศวกรของเราเกี่ยวกับห้องสมุดการสื่อสารที่ฉันทำงานอยู่

แทนที่จะเป็นคำสั่งฉันมีคลาสขอแล้วฉันก็มี RequestHandler การออกแบบนั้นเหมือนกับสิ่งที่คุณกำลังอธิบาย ฉันคิดว่าส่วนหนึ่งของความสับสนที่คุณมีคือคุณเห็นคำภาษาอังกฤษ "คำสั่ง" และคิดว่า "คำกริยาการกระทำ ... ฯลฯ " ทันที

แต่ในการออกแบบนี้ให้คิดว่า Command (หรือ Request) เป็นตัวอักษร หรือสำหรับผู้ที่ไม่ทราบว่าบริการไปรษณีย์คืออะไรคิดอีเมล มันเป็นเพียงเนื้อหาแยกออกจากวิธีการที่เนื้อหาควรจะดำเนินการ

ทำไมคุณถึงทำเช่นนี้? ในกรณีที่ง่ายที่สุดของรูปแบบคำสั่งไม่มีเหตุผลและคุณสามารถให้คลาสนี้ทำงานได้โดยตรง อย่างไรก็ตามการทำ decoupling ในแบบของคุณนั้นสมเหตุสมผลถ้าการกระทำ / คำสั่ง / คำขอของคุณต้องเดินทางไกล ตัวอย่างเช่นข้ามซ็อกเก็ตหรือไพพ์หรือระหว่างโดเมนและโครงสร้างพื้นฐาน หรืออาจจะอยู่ในสถาปัตยกรรมของคุณคำสั่งของคุณจะต้องคงอยู่ (เช่นตัวจัดการคำสั่งสามารถทำ 1 คำสั่งได้ในแต่ละครั้งเนื่องจากเหตุการณ์บางอย่างของระบบคำสั่ง 200 คำสั่งมาถึงและหลังจากกระบวนการ 40 ครั้งแรกได้รับการปิด) ในกรณีดังกล่าวการมีคลาสข้อความอย่างเดียวอย่างง่ายมันจะกลายเป็นเรื่องง่ายมากที่จะทำให้เป็นอนุกรมส่วนของข้อความใน JSON / XML / binary / อะไรก็ตามและส่งมันลงท่อไปจนกว่าตัวจัดการคำสั่งของมันพร้อมที่จะประมวลผล

ข้อดีอีกประการของ decoupling Command จาก CommandHandler คือตอนนี้คุณมีตัวเลือกของลำดับชั้นการสืบทอดขนาน ตัวอย่างเช่นคำสั่งทั้งหมดของคุณอาจได้รับมาจากคลาสคำสั่งฐานที่รองรับการทำให้เป็นอนุกรม และบางทีคุณอาจมีตัวจัดการคำสั่ง 4 จาก 20 ตัวที่มีความคล้ายคลึงกันมากตอนนี้คุณสามารถหาค่าจากคลาสฐานของตัวจัดการที่มา หากคุณต้องมีข้อมูลและการจัดการคำสั่งในชั้นหนึ่งความสัมพันธ์ประเภทนี้จะหมุนวนอย่างไม่สามารถควบคุมได้

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


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

@ ความสุข: คุณรู้ได้อย่างไรว่าบริบทคืออะไร? เว้นแต่ว่าสถาปัตยกรรม S # arp เป็นสิ่งที่พิเศษทั้งหมดที่ฉันเห็นคือการประกาศในชั้นเรียนสองสามชั้นและคุณไม่รู้ว่าจะใช้งานอย่างไรในส่วนที่เหลือของแอปพลิเคชัน หากคุณไม่ชอบตัวเลขที่ฉันเลือกเช่น 50 ให้เลือกอย่าง 50 ต่อวินาที หากนั่นยังไม่เพียงพอเลือก 1,000 ต่อวินาที ฉันแค่พยายามยกตัวอย่าง หรือคุณไม่คิดว่าในบริบทนี้เขาจะมีคำสั่งมากมาย
DXM

ยกตัวอย่างเช่นโครงสร้างที่แน่นอนจะเห็นที่นี่weblogs.asp.net/shijuvarghese/archive/2011/10/18/... และไม่มีที่ไหนที่มันพูดสิ่งที่คุณพูด และเกี่ยวกับความเร็วปัญหาคือคุณใช้อาร์กิวเมนต์ 'ประสิทธิภาพ' โดยไม่มีการทำโปรไฟล์ หากคุณมีข้อกำหนดสำหรับปริมาณงานเช่นนั้นคุณจะไม่ใช้สถาปัตยกรรมทั่วไป แต่สร้างสิ่งที่พิเศษกว่า
ร่าเริง

1
ให้ฉันดูว่านี่เป็นจุดสุดท้ายของคุณหรือไม่: OP ขอตัวอย่างและฉันควรจะพูดตัวอย่างเช่นก่อนอื่นคุณออกแบบวิธีที่ง่ายและแอปพลิเคชันของคุณทำงานจากนั้นขยายขนาดและขยายสถานที่ที่คุณใช้รูปแบบคำสั่ง คุณเริ่มใช้งานจริงและรับ 10,000 เครื่องพูดคุยกับเซิร์ฟเวอร์ของคุณและเซิร์ฟเวอร์ของคุณยังคงใช้สถาปัตยกรรมดั้งเดิมของคุณจากนั้นทำโปรไฟล์และระบุปัญหาจากนั้นคุณสามารถแยกข้อมูลคำสั่งออกจากการจัดการคำสั่ง แต่หลังจากที่คุณทำโปรไฟล์แล้ว มันจะทำให้คุณมีความสุขมากขึ้นหรือไม่ถ้าฉันรวมทุกอย่างไว้ในคำตอบ? เขาขอตัวอย่างฉันให้เขาคนหนึ่ง
DXM

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

2

รูปแบบคำสั่งปกติเกี่ยวกับการมีข้อมูลและพฤติกรรมในชั้นเดียว 'รูปแบบคำสั่ง / ตัวจัดการ' ชนิดนี้แตกต่างกันเล็กน้อย ข้อได้เปรียบเพียงอย่างเดียวเมื่อเทียบกับรูปแบบปกติคือการเพิ่มความได้เปรียบของการไม่มีคำสั่งของคุณขึ้นอยู่กับกรอบงาน ตัวอย่างเช่นคำสั่งของคุณอาจต้องการการเข้าถึงฐานข้อมูลดังนั้นจึงจำเป็นต้องมีบริบทหรือเซสชัน DB บางประเภทซึ่งหมายความว่าขึ้นอยู่กับกรอบงาน แต่คำสั่งนี้อาจเป็นส่วนหนึ่งของโดเมนของคุณเพื่อให้คุณไม่ต้องการให้ขึ้นอยู่กับกรอบตามพึ่งพาผกผันหลักการ การแยกพารามิเตอร์อินพุทและเอาท์พุทออกจากพฤติกรรมและการมีตัวเลือกจ่ายงานบางส่วนเพื่อต่อสายพวกเขาสามารถแก้ไขปัญหานี้ได้

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

นอกจากนี้ nitpick เล็กน้อย เพียงเพราะมันมี Command ในชื่อไม่ได้ทำให้มันเป็นส่วนหนึ่งของ CQRS นั่นเป็นเรื่องพื้นฐานที่สำคัญกว่ามาก โครงสร้างชนิดนี้สามารถให้บริการทั้งคำสั่งและเป็นคิวรีแม้ในเวลาเดียวกัน


ฉันเห็นลิงค์weblogs.asp.net/shijuvarghese/archive/2011/10/18/…คุณได้ชี้ให้เห็นแล้ว แต่ฉันไม่เห็นสัญญาณของรถบัสใน S # arp Arch code ที่ฉันมี ดังนั้นฉันเดาว่าการแยกเช่นนี้ในกรณีของฉันจะกระจายคลาสและตรรกะสาดเท่านั้น
rgripper

1
@rgripper แล้วคุณค้นหาไม่ถูกต้อง github.com/sharparchitecture/Sharp-Ar Architecture/blob/…และgithub.com/sharparchitecture/Sharp-Ar
Architecture/blob/…

อืมขอบคุณที่ชี้ให้เห็น จากนั้นเคสของฉันยิ่งแย่ลงเล็กน้อยเพราะในรหัสฉันมี ICommandProcessor เป็น IOC'ed และแก้ไขให้กับ CommandProcessor (ซึ่งตัวเองกำลังทำ IOC สำหรับตัวจัดการคำสั่ง) - องค์ประกอบที่เป็นโคลน และในโครงการดูเหมือนจะไม่มีกรณีธุรกิจสำหรับฮาเดลเลอร์มากกว่าหนึ่งคนสำหรับคำสั่ง
rgripper
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.