สรุปการใช้ตัวแปรภายในโค้ด


11

ฉันอยากจะรู้ว่ามันเป็นการปฏิบัติที่ดีที่จะทำให้ตัวแปรทั่วไป (ใช้ตัวแปรเดียวเพื่อเก็บค่าทั้งหมด)
ลองพิจารณาตัวอย่างง่ายๆ

 Strings querycre,queryins,queryup,querydel; 
    querycre = 'Create table XYZ ...';
    execute querycre ;
    queryins = 'Insert into XYZ ...';
    execute queryins ;
    queryup  = 'Update  XYZ set ...';
    execute queryup;
    querydel = 'Delete from XYZ ...';
    execute querydel ;

และ

 Strings query; 
    query= 'Create table XYZ ... ';
    execute query ;
    query= 'Insert into XYZ ...';
    execute query ;
    query= 'Update  XYZ set ...';
    execute query ;
    query= 'Delete from XYZ ...';
    execute query ;

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

การมีตัวแปรมากเกินไปจะขัดขวางการทำงานของฉันด้วยหรือไม่?

PS: โปรดอย่าตอบ wrt รหัสในตัวอย่างมันเป็นเพียงการถ่ายทอดสิ่งที่ฉันหมายถึงจริงๆ


แน่นอนว่าคุณใช้ตัวแปรเดียวกันซ้ำ ... เพราะคุณได้กำหนดไว้ในฟังก์ชั่น นั่นคือสิ่งที่ฟังก์ชั่นสำหรับ
zzzzBov

คำตอบ:


26

ต้องถามตัวเองคำถามนี้มีกลิ่นแรงที่คุณไม่ได้ติดตาม DRY (อย่าทำซ้ำตัวเอง) สมมติว่าคุณมีสิ่งนี้ในภาษาที่มีความโค้งงอสมมุติ:

function doFoo() {
    query = "SELECT a, b, c FROM foobar WHERE baz = 23";
    result = runQuery(query);
    print(result);

    query = "SELECT foo, bar FROM quux WHERE x IS NULL";
    result = runQuery(query);
    print(result);

    query = "SELECT a.foo, b.bar FROM quux a INNER JOIN quuux b ON b.quux_id = a.id ORDER BY date_added LIMIT 10";
    result = runQuery(query);
    print(result);
}

Refactor ที่เป็น:

function runAndPrint(query) {
    result = runQuery(query);
    print(result);
}

function doFoo() {
    runAndPrint("SELECT a, b, c FROM foobar WHERE baz = 23");
    runAndPrint("SELECT foo, bar FROM quux WHERE x IS NULL");
    runAndPrint("SELECT a.foo, b.bar FROM quux a INNER JOIN quuux b ON b.quux_id = a.id ORDER BY date_added LIMIT 10");
}

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


2
ฉันรักหลักการ DRY :)
artjom

1
@tdammers มันดีที่มีโค้ดแค่ 2 บรรทัดในฟังก์ชั่นหรือไม่พิจารณาว่าฉันมีฟังก์ชั่นนี้ doFoo () {print (runQuery ("Selct a, b, c จาก XYZ"));}
Shirish11

1
ไม่การโทรสแต็คจะไม่เพิ่มขึ้น - การโทรแต่ละครั้งจะrunAndPrintผลักเฟรมสแต็กหนึ่งเฟรมเมื่อคุณเรียกใช้จากนั้นจะปรากฏขึ้นอีกครั้งเมื่อฟังก์ชันออก หากคุณเรียกมันว่าสามครั้งมันจะทำคู่ push / pop สามคู่ แต่สแต็กจะไม่เติบโตมากกว่าหนึ่งเฟรมต่อครั้ง คุณควรกังวลเกี่ยวกับความลึกของการโทรด้วยฟังก์ชั่นวนซ้ำ
tdammers

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

1
@JamesAnderson: มันเป็นตัวอย่างที่มีการวางแผนมาบ้าง แต่มันทำหน้าที่แสดงให้เห็นถึงประเด็น มันไม่เกี่ยวกับจำนวนบรรทัดของโค้ดที่คุณมี มันกี่ครั้งที่คุณระบุความจริงเดียวกัน นั่นคือสิ่งที่ DRY กำลังทำอยู่รวมถึงหลักการ Single Source of Truth กฎ Thou Shalt Not Copy-Paste ฯลฯ
tdammers

14

โดยปกตินี่เป็นวิธีปฏิบัติที่ไม่ดี

การใช้ตัวแปรซ้ำเป็นวิธีนี้สามารถสร้างโค้ดที่ทำให้อ่านสับสนได้

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

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

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


ประสิทธิภาพของระบบได้รับผลกระทบจากอะไรบ้าง
Shirish11 11

@ Shirish11 - มันอาจ ขึ้นอยู่กับคอมไพเลอร์ภาษาสภาพแวดล้อมและตัวแปรอื่น ๆ
Oded

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

7

รหัสที่บันทึกด้วยตนเองนั้นง่ายต่อการอ่านและการบำรุงรักษา

ปฏิบัติตามหลักการของความคลาดเคลื่อนน้อยที่สุดและกฎเกณฑ์ของcode-as-document : ใช้หนึ่งตัวแปรสำหรับหนึ่งเป้าหมายเพื่อให้ทั้งสองใช้งานง่ายต่อการเข้าใจและโค้ดอ่านง่ายโดยไม่มีคำอธิบาย

รหัสที่มีโครงสร้างที่ถูกต้องนั้นง่ายกว่า (ถูกกว่า) ถึง (ใช้ซ้ำ)

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

ด้วยวิธีนี้คุณจะได้อย่างมีประสิทธิภาพ:

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

ตัวอย่าง:

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

ตัวอย่างของคุณ 1:

Strings querycre,queryins,queryup,querydel; 
    querycre = 'Create table XYZ ...';
    execute querycre ;
    queryins = 'Insert into XYZ ...';
    execute queryins ;
    queryup  = 'Update  XYZ set ...';
    execute queryup;
    querydel = 'Delete from XYZ ...';
    execute querydel ;

ตัวอย่างของคุณ 2:

 Strings query; 
    query= 'Create table XYZ ...';
    execute query ;
    query= 'Insert into XYZ ...';
    execute query ;
    query= 'Update  XYZ set ...';
    execute query ;
    query= 'Delete from XYZ ...';
    execute query ;

ตัวอย่างที่ 3 (หลอกรหัสปลอม):

def executeQuery(query, parameters...)
    statement = prepareStatement(query, parameters);
    execute statement;
end

// call point:
executeQuery('Create table XYZ ... ');
executeQuery('Insert into XYZ ...');
executeQuery('Update  XYZ set ...');
executeQuery('Delete from XYZ ...');

ผลประโยชน์แสดงให้เห็นว่ามีการใช้ซ้ำตามปกติ

เรื่องเล็ก ๆ น้อยส่วนบุคคล

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

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

มีอะไรให้ฉัน

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

ตามส่วนขยายสิ่งนี้นำไปสู่:

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

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


2

ในแง่ของการออกแบบรหัส

โดยทั่วไปก็ไม่เป็นไรตัวแปรที่นำมาใช้ในการจัดเก็บค่าที่แตกต่าง - หลังจากทั้งหมดที่ว่าทำไมพวกเขาจะเรียกตัวแปรเพราะค่าที่เก็บไว้ในพวกเขาแตกต่างกัน - ตราบใดที่ค่าไม่ได้เป็นเพียงชนิดเดียวกัน แต่ยังหมายถึงสิ่งเดียวกัน ตัวอย่างเช่นแน่นอนว่าไม่ควรนำcurrentQueryตัวแปรมาใช้ใหม่ที่นี่:

for currentQuery in queries:
    execute query;

โดยปกติจะมีการวนซ้ำดังนั้นคุณต้องนำตัวแปรมาใช้ใหม่ แต่ถึงแม้ว่าจะไม่มีการวนซ้ำก็ตามก็จะไม่เป็นไร หากค่าไม่ได้หมายความว่าสิ่งเดียวกันใช้ตัวแปรแยกต่างหาก

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

ในแง่ของประสิทธิภาพ

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

ตัวอย่างเช่นgcc -O2สร้างไบนารีเดียวกันที่แน่นอนและความแตกต่างของประสิทธิภาพเดียวที่ฉันรู้คือขนาดของตารางสัญลักษณ์ระหว่างการรวบรวม - เล็กน้อยอย่างสมบูรณ์เว้นแต่คุณจะย้อนเวลากลับไปในยุค 60

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


0

ฉันคิดว่าการใช้ตัวแปรซ้ำเป็นส่วนใหญ่

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


-1

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


ฉันเพิ่งยกตัวอย่างง่ายๆเพื่อให้ผู้อ่านเข้าใจสิ่งที่ฉันต้องการได้ง่ายขึ้น รหัสของฉันซับซ้อนกว่านี้มาก
Shirish11 11

-2

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

{
    String query = 'Create table XYZ ...';
    execute query;
}
{
    String query = 'Insert table XYZ ...';
    execute query;
}
And so on...

(ณ จุดนี้ฉันอาจพิจารณาวิธีแก้ปัญหาของ tdammers )

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

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


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

@haylem: ในกรณีจริง ๆ เช่นเดียวกับที่คุณกำลังเพิ่มวิธีการช่วยเหลือซึ่งมีคนอ่านรหัสต้องไปและค้นหา (และบางคนอาจมีปัญหากับวิธีการของผู้ช่วยเหลือและต้องค้นหาสถานที่ทั้งหมดที่เรียกว่า) ความคมชัดน้อยลงเกี่ยวกับรหัสจำนวนเท่ากัน ในกรณีที่มีความซับซ้อนมากขึ้นฉันไปกับวิธีการแก้ปัญหาของฉันแล้วมีtdammer 's ฉันตอบคำถามนี้เป็นส่วนใหญ่เพื่อชี้ให้เห็นถึงปัญหาที่คลุมเครือ (เป็นที่ยอมรับ แต่น่าสนใจ) ที่เป็นตัวแปรที่ก่อให้เกิดทั้งมนุษย์และเครื่องมือเพิ่มประสิทธิภาพ
RalphChapin

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