รูปแบบการออกแบบ OOP ที่ดีที่สุดสำหรับลำดับของการดำเนินการ


11

ฉันกำลังทำงานกับแอปพลิเคชันซึ่งเป็นโมดูลที่ดำเนินการทางการเงินต่อไปนี้ตามลำดับ:

เมื่อผู้ใช้ร้องขอจำนวนเงินที่ต้องการโอนเข้าบัญชีธนาคารของเธอ:

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

ควรบันทึกผลลัพธ์ของการดำเนินการข้างต้นทั้งหมด

หากเงื่อนไขข้างต้นทั้งหมดเป็นไปตามธุรกรรมจะดำเนินการ ในอนาคตอาจมีการตรวจสอบเพิ่มเติม

รูปแบบการออกแบบเชิงวัตถุแบบใดที่เหมาะสมที่สุดสำหรับกรณีข้างต้น


3
อย่ามองหารูปแบบการออกแบบเพื่อแก้ปัญหา ใช้รูปแบบการออกแบบเพื่อสื่อสารโซลูชันที่ถูกต้อง programmers.stackexchange.com/questions/70877/…ทำตามหลักการของ SOLID และคุณจะไม่ผิดพลาด
pdr

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

10
นี่คือลักษณะที่ดีของรูปแบบคือ: "พวกเขา [รูปแบบ] ให้การทำงานที่เป็นรูปธรรมและปรับเปลี่ยนได้เพื่อแก้ไขปัญหาที่เกิดขึ้นซ้ำ ๆ ในบางสถานการณ์ในระหว่างการพัฒนาซอฟต์แวร์จากองค์กรไปจนถึงบริบทการเขียนโปรแกรม" [POSA5, p. 30] ดังนั้นจากมุมมองนี้เป็นที่ชัดเจนโดยสิ้นเชิงว่าการมองหารูปแบบในฐานะที่เป็นวิธีการแก้ปัญหาที่ปรับเปลี่ยนได้เป็นวิธีการที่ถูกต้อง
Jonny Dee

3
คุณกำลังขอสิ่งก่อสร้างเชิงวัตถุเพื่ออธิบายขั้นตอนการเขียนโปรแกรมแบบเก่าธรรมดาหรือไม่?
mouviciel

4
ปฏิบัติตามหลักการ KISS จนถึงปัญหาของคุณสามารถแก้ไขได้ด้วยคำสั่ง 3 "ถ้า" ในวิธีการเดียว อย่าพยายามใช้รูปแบบการออกแบบเพียงเพื่อความเท่ห์ ทุกครั้งที่คุณเขียนชั้นเรียนเพิ่มเติมให้คิดเสมอว่า: ฉันต้องการสิ่งนั้นจริงหรือ
Eiver

คำตอบ:


13

มันเสียงเหมือนสิ่งที่คุณกำลังมองหาเป็นห่วงโซ่ของความรับผิดชอบ ในกรณีนี้คุณอาจมีคลาสต่อไปนี้:

  • TransactionValidatorBase ชั้นฐานนามธรรม
  • TransactionTimeValidator
  • TransactionAmountValidator
  • TransactionAccountValidator

ที่ถูกล่ามโซ่ไว้ด้วยกันเพื่อนำไปใช้กฎที่คุณระบุ

อ่าน Furter


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

ฉันคิดว่าคุณสามารถมี Chain of R ได้ในระดับเดียวฉันไม่คิดว่าจะยากที่จะคืนค่าจาก Chain ด้วยการลบเล็กน้อย แต่ละระดับจะต้องสื่อสารถึงการยึดมั่นกับอินเทอร์เฟซดั้งเดิมบางอย่างและจะต้องรับอินพุตจากด้านล่างเนื่องจากอินพุตดังกล่าวสอดคล้องกับอินเตอร์เฟสดั้งเดิม เมื่อต้องการความสมบูรณ์ของอินเตอร์เฟซระหว่างสองระดับของเชนที่มีความใกล้ชิดกันมากขึ้นการลบสามารถโพลี morphed เพื่อสนับสนุน
Andyz Smith

3

หากลำดับขั้นตอนของคุณกำลังทำหน้าที่ตรวจสอบความถูกต้องเป็นส่วนใหญ่ (เหมือนที่คุณเป็น) โดยไม่ปิดบังอินพุตฉันคิดว่าเป็นรูปแบบ "Chain of Responsibility" ตามที่อธิบายไว้ในคำตอบของเขาโดย @pswg

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

นี่เป็นบทความสองข้อเกี่ยวกับเรื่องนี้: การ
รวบรวมทางท่อโดย Martin Fowler
การอภิปรายเชิงทฤษฎีเพิ่มเติมเกี่ยวกับรูปแบบ


2

รูปแบบที่ถูกต้องที่นี่ขึ้นอยู่กับบริบท ก่อนที่จะเลือกรูปแบบที่เฉพาะเจาะจงใด ๆ ฉันจะพยายามหาคำตอบสำหรับคำถามเหล่านั้น:

  • จำเป็นต้องสร้างการรวมกันของการตรวจสอบ (1,2,3) ที่แตกต่างกันในเวลาทำงานหรือไม่?
  • พวกเขาต้องการตัวแปรเดียวกันเพื่อดำเนินการของพวกเขาหรือพวกเขาแตกต่างกันมาก?
  • ข้อความแสดงข้อผิดพลาดมีความแม่นยำเพียงใด
  • ในกรณีของความล้มเหลวผู้ใช้ลองใหม่อีกครั้งจาก (1) ขั้นตอนเสมอ?
  • วิธีการจัดการภาวะพร้อมกัน?
  • แต่ละวิธีเพิ่มบางสิ่งลงในคำขอหรือตรวจสอบความถูกต้องหรือไม่? (พูดว่า acct id เริ่มต้นหรือไม่)

ตามความรู้สึกของลำไส้ฉันจะใช้มันเป็นวิธีการธรรมดาที่มีพารามิเตอร์รวมสำหรับรหัสข้อผิดพลาด

public void DoTransaction(IErrorAgregator error, TransactionRequest request)
{
    if(!IsTransactionInCertainTimePeriod(request, error)) return;
    if(!IsTransactionAmountInUserBounds(request, error)) return;
    if(!UserHaveDefaultAccount(request, error)) return;
    bankingTransactor.PerformTransaction(request);
}

อาจเป็นความคิดที่ดีที่จะวาง DoTransaction ในส่วนติดต่อ "ITransactionValidationStragegy" และสร้างเลเยอร์แบบซุปเปอร์เลเยอร์ซึ่งจะมีรหัสตรวจสอบสำเร็จรูป

อย่างไรก็ตามในการออกแบบนี้ฉันสันนิษฐานว่าตรรกะการตรวจสอบจะถูกกำหนดในเวลารวบรวม


0

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

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

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


-2

ตามความเข้าใจของฉันสิ่งที่จำเป็นต้องสามารถติดตั้งในรูปแบบคำสั่งเช่นด้านล่าง การออกแบบชั้นสามารถทำได้ตามด้านล่าง

interface Transaction{
void performAction();
}

class Banking{

void moneyValidation(){
//Validate Here
}

void timeValidation(){
//validate Here
}
}

class TimeValidation implements Transaction{

public Banking bank;

public TimeValidation (Banking bnk){
bank=bnk;
}

void performAction(){
bnk.timeValidation();
}


class MoneyValidation Implements Transaction{

public Banking bank;

public MoneyValidation(Banking bnk;){
bank=bnk;
}

void performAction(){
bnk.moneyValidation();
}
}


class Control{

private List val_list=new ArrayList();

void storeValidation(Transaction trans){
val_list.add(trans);
trans.performAction(val_list.getFirstAndRemove());
}
}

//Same for other validation classes

คลาสลูกค้าของคุณจะมีข้อมูลโค้ดต่อไปนี้:

Banking bnk = new Banking();
MoneyValidation m_val = new MoneyValidation (bnk);
TimeValidation t_val = new TimeValidation (bnk);
Control ctrl = new Control();
ctrl.storeValidation(m_val);
ctrl.storeValidation(t_val);

นี่คือตามความเข้าใจของฉันกับสถานการณ์ที่ได้รับข้างต้น


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