ฟังก์ชั่นชื่ออะไรที่ไม่โต้แย้งและส่งคืนอะไร? [ปิด]


80

ในjava.util.functionแพ็คเกจของ Java 8 เรามี:

  • ฟังก์ชัน : รับหนึ่งอาร์กิวเมนต์สร้างผลลัพธ์เดียว
  • ผู้บริโภค : รับหนึ่งอาร์กิวเมนต์สร้างอะไรขึ้นมา
  • ผู้จัดจำหน่าย : ไม่ต้องโต้เถียงสร้างผลลัพธ์เดียว
  • ... : กรณีอื่น ๆ ที่จัดการแบบดั้งเดิมอาร์กิวเมนต์ 2 ข้อ ฯลฯ ...

แต่ฉันต้องจัดการกับ " ไม่มีข้อโต้แย้งสร้างอะไร "

ไม่มีอะไรสำหรับสิ่งนี้java.util.functionnalค่ะ

ดังนั้นคำถามคือ:

ชื่อ ' ฟังก์ชั่นที่ไม่โต้แย้งและไม่ส่งคืนอะไร '?

ใน Java 8 นิยามของมันจะเป็น:

@FunctionalInterface
public interface InsertANameHere {
    void execute();
}

ผู้บริหารอยู่แล้วและมีวัตถุประสงค์อื่น: " วัตถุที่ดำเนินการส่งงานที่เรียกใช้งานได้ " ลายเซ็นไม่ตรงกัน ( execute(Runnable):void) และไม่ได้เป็นอินเทอร์เฟซที่ใช้งานได้

มีRunnableอยู่ แต่มีการเชื่อมโยงอย่างมากกับบริบทเธรด:

  • แพคเกจไม่java.langjava.util.function
  • สถานะ javadoc: " อินเทอร์เฟซที่เรียกใช้ควรนำมาใช้โดยคลาสใด ๆ ที่อินสแตนซ์ตั้งใจที่จะดำเนินการโดยเธรด "
  • ชื่อ "Runnable" แนะนำให้เรียกใช้รหัสบางอย่างภายในเธรด

28
"แต่ไม่มีอะไรเลยสำหรับ" ไม่โต้แย้งไม่มีอะไรเลย "" - Runnable ?
user11153

11
ฉันคิดว่า javadoc สำหรับRunnableนั้นล้าสมัยแล้ว ณ จุดนี้เนื่องจาก Runnable ยังถูกใช้โดยคลาสอื่นมากกว่าThread( Executorตัวอย่าง)
SpaceTrucker

13
@superbob นั่นไม่ได้หมายความว่าRunnables สามารถเป็นได้.run()โดยThreads เท่านั้น ในความเป็นจริงพวกเขามักใช้เพื่อวัตถุประสงค์ตรงตามที่อธิบายไว้ในคำถาม
blgt

5
@superbob นั่นคือจุดประสงค์เริ่มต้น แต่เนื่องจาก Java 8 มันถูก "ดัดแปลง" เป็นส่วนต่อประสานการทำงาน ดังนั้นนี่คือเหตุผลที่คุณไม่พบสิ่งใดในjava.util.function แพ็คเกจ
user11153

5
Semi-Snark: ImpureFuntion เพราะมันขึ้นอยู่กับผลข้างเคียงเท่านั้นไม่เช่นนั้นจะไม่มี op ( en.wikipedia.org/wiki/Pure_function#Impure_functions ) เพิ่มเติม Seriosuly: Imperative (ทำอะไร) ซึ่งอย่างน้อยก็จะตรงกับความหมายของโมฆะเอ็กซีคิวต์ ();
Kristian H

คำตอบ:


71

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

การใช้กระบวนทัศน์แบบหลอกทำงานไม่ได้หมายความว่าหลักการตั้งชื่อปกติควรออกไปนอกหน้าต่าง อินเทอร์เฟซควรตั้งชื่อตามสิ่งที่พวกเขาทำอยู่เสมอไม่ใช่แนวคิดการสร้างประโยคทั่วไป UndoFunctionหากฟังก์ชั่นที่มีอยู่เข้าไปในกองยกเลิกพวกเขาควรจะได้รับการตั้งชื่อ หากพวกเขาจะเรียกว่าจากเหตุการณ์ที่เกิดขึ้น GUI GUIEventHandlerพวกเขาควรจะได้รับการตั้งชื่อ เพื่อน ๆ จะไม่ปล่อยให้เพื่อนปฏิบัติตามอนุสัญญาการตั้งชื่อที่ไม่ดี


Procedureก็ดีเหมือนกัน สำหรับบริบทนี้ฉันกำลังพัฒนาไลบรารีทั่วไปที่ต้องการจัดการ "โครงสร้าง" ชนิดนี้
superbob

18
ฉันชอบProcedureตั้งแต่ปาสกาลของฉัน A Procedureมีผลข้างเคียงFunctionไม่ได้ เนื่องจากคุณไม่ส่งคืนค่าสิ่งเดียวที่ทำได้คือมีผลข้างเคียง
Spencer Rathbun

ฉันอาจจะมีแนวโน้มที่จะใช้ProcedureRIR<T1,T2>สำหรับการvoid proc(T1, int, T2)และเช่นเดียวกันประเภทอื่น ๆ - อาจสร้างที่สุดของพวกเขาเกี่ยวกับความต้องการมากกว่าการพยายามที่จะยัดเยียดในทุกชุดเป็นไปได้ของประเภท
supercat

1
ที่จริงแล้วการเขียนโปรแกรมที่ใช้งานได้จริงไม่สนับสนุนการตั้งชื่อสไตล์ฮังการี นี่เป็นแนวคิดของกระบวนทัศน์ OO มากกว่าความสามารถในการทำงาน
slebetman

3
If the functions are placed into an undo stack, they should be named UndoFunction.มีความแตกต่างระหว่างการตั้งชื่อฟังก์ชั่นและให้มันเป็นประเภทที่แตกต่างกัน ในรูปแบบการทำงานที่คุณจะไม่สร้างUndoFunctonประเภทเพราะตอนนี้คุณไม่สามารถผ่านไปflip, curry, compose, filter, mapฯลฯ ในความเห็นของผมว่าเป็นเหตุผลที่แท้จริงในการตัดสินใจของ Java ที่จะให้ฟังก์ชั่นที่แตกต่างกันกับ arities ชื่อแตกต่างกันคือโง่ แน่นอนถ้าคุณจะใช้ผลข้างเคียงเรียกมันว่าอะไรก็ตาม คุณโยนหน้าต่างออกไปแล้วและคุณไม่ได้ใช้ฟังก์ชั่น
Doval

33

Runnableในโลกจาวาจะเรียกว่า ในโลก C # Actionจะเรียกว่า

แต่มีชื่อที่ดีกว่าซึ่งเหมาะสมอย่างยิ่งในมุมมองที่กว้างขึ้นของสิ่งต่าง ๆ

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

ดังนั้นใน Java ฉันมีชุดอินเตอร์เฟสการทำงานที่ฉันเรียกProcedures กำหนดไว้ดังนี้:

public interface Procedure
{
    void invoke();
}

public interface Procedure1<T1>
{
    void invoke( T1 argument1 );
}

... (คุณได้ภาพ)

และฉันยังมีชุดอินเทอร์เฟซที่คล้ายกันที่เรียกว่าFunctions ซึ่งนิยามในลักษณะที่คล้ายกันโดยพารามิเตอร์ทั่วไปตัวแรกคือชนิดส่งคืน:

public interface Function<R>
{
    R invoke();
}

public interface Function1<R,T1>
{
    R invoke( T1 argument1 );
}

ดังนั้นจุดของฉันที่นี่คือProcedureชื่อที่ดีมากเพราะมันเหมาะอย่างยิ่งในมุมมองที่กว้างขึ้นของสิ่งต่าง ๆ หากภายหลังคุณตัดสินใจที่จะมีส่วนต่อประสานการทำงานที่คล้ายกันพร้อมวิธีการที่ยอมรับอาร์กิวเมนต์หรือคืนค่าคุณจะพบกับสิ่งนี้

หมายเหตุ:โดยพื้นฐานแล้วฉันเห็นด้วยกับการยืนยันของ Karl Bielefeldt ว่า "หลักการตั้งชื่อปกติควร [ไม่] ออกไปนอกหน้าต่าง" และ "การเชื่อมต่อควรตั้งชื่อตามสิ่งที่พวกเขาทำอยู่เสมอ แต่โปรดทราบว่าแม้เขาจะอนุญาตให้ "เกือบตลอด" บางครั้งมีความต้องการขั้นตอนและฟังก์ชั่น (โดยไม่ระบุชื่อ) และนั่นคือสิ่งที่ OP ขอและนั่นคือสิ่งที่ฉันตอบ

แก้ไข 2017-11-10:

คุณอาจจะถามว่าทำไมFunction1<R,T1>แทนFunction1<T1,R>? มันสามารถไปได้ทั้งสองทาง แต่ฉันมีความพึงพอใจกับค่าตอบแทนทางด้านซ้ายเพราะฉันชอบที่จะปฏิบัติตามการตั้งชื่อ 'แปลงจาก' (ปลายทางจากแหล่งที่มา) ตรงข้ามกับ 'แปลงเป็น' (แหล่งที่มาเป็น -destination) อนุสัญญา (ซึ่งเป็นอุบัติเหตุมากกว่าการประชุมจริง ๆ แล้วในแง่ที่มากที่สุดไม่มีใครเคยคิดเลยเพราะถ้าพวกเขาให้ความคิดใด ๆ พวกเขาจะมาถึงที่ประชุม 'เปลี่ยนจาก' )

ฉันอ่านเกี่ยวกับเรื่องนี้ในJoel Spolksy - การทำผิดรหัสดูผิดมันเป็นบทความที่ยาวมากซึ่งฉันแนะนำให้อ่านอย่างครบถ้วน แต่ถ้าคุณต้องการที่จะข้ามไปยังกรณีที่อยู่ในมือค้นหา 'TypeFromType' แต่เพื่อ ให้ TL; DR ความคิดนั้นmyint = intFromStr( mystr )ดีกว่าmyint = strToInt( mystr )เพราะในกรณีแรกชื่อของประเภทนั้นใกล้เคียงกับค่าที่เกี่ยวข้องดังนั้นคุณจะเห็นว่า 'int' ตรงกับ 'int' และ ตรงกับ 'str' กับ 'str'

ดังนั้นโดยการขยายฉันมักจะสั่งสิ่งต่าง ๆ ในลักษณะที่พวกเขาจะปรากฏในรหัส


1
วิธีแก้ปัญหานี้ดีมากดูเหมือนกันกระสุนได้มากกว่าผู้ผลิต, ผู้บริโภค, BiFunction, ของจาวาเอง ... เพราะมันวางทุกอย่างลงในสองแนวคิดเท่านั้น มันทำให้ฉันนึกถึง @Karl Bielefeldt ตอบเกี่ยวกับ " ทางเลือกของ Java ในการทำเช่นนั้นด้วยชื่อที่แยกต่างหากสำหรับทุก arity [ที่] โง่ " "ข้อเสีย" อย่างเดียวเท่านั้นคือมันไม่ได้จัดการประเภทดั้งเดิมและการรวมกันของพวกเขา (สิ่งที่สนุกเช่น DoubleToLongFunction, ToLongBiFunction, ... ) แต่ดั้งเดิมเป็นข้อกังวลอื่น ...
superbob

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

1
ถ้าผมสามารถที่จะยอมรับคำตอบที่ 2 ผมจะเลือกคุณขอบคุณที่ขั้นตอนยังไม่มีฟังก์ชั่นNข้อเสนอแนะ ฉันยังยกมันขึ้นมา
superbob

ทำไมถึงไม่ได้Function1<T1, R>?
ErikE

@ErikE เป็นคำถามที่ดีมากและฉันแก้ไขโพสต์ของฉันเพื่อตอบ
Mike Nakis

18

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

เมื่อพูดถึงเรื่องนี้ก็มีActionตัวแทนทั่วๆไปใน. NET ไม่เหมือนกับ Java's ซึ่งConsumerสามารถใช้อาร์กิวเมนต์ตั้งแต่ 0 ถึง 16 ในคำอื่น ๆ รุ่นที่ง่ายของมันจะใช้เวลาไม่มี - ดูMSDN

และเนื่องจากชื่อไม่ได้บอกเป็นนัยว่ามีอะไรที่จะ "กิน" มันจึงดูเหมือนเป็นตัวเลือกชื่อที่ดี


1
Commandดี. อาจสับสนกับรูปแบบคำสั่งแต่อาจเป็นวิธีแก้ปัญหา
superbob

7
ฉันชอบมากกว่าAction Commandคำสั่งฟังดูเหมือนบางสิ่งที่ได้รับและประเมินผลในขณะที่การดำเนินการจะดำเนินการสำหรับผลข้างเคียง
Bergi

7
อืมม ... วิธีที่สามารถมันไม่ได้เป็นรูปแบบคำสั่ง? คุณได้สร้างเอนทิตีคำสั่ง! มันยังมีexecute()วิธีการแบบชื่อ
0_o

1
ไม่ชอบข้อเสนอแนะของ Action เนื่องจากเป็นอินเทอร์เฟซ Swing ทั่วไป (และดี) คำสั่งนั้นสมเหตุสมผล
949300

@ user949300 แต่ขึ้นอยู่กับบริบท - Java เป็นโลกที่ยิ่งใหญ่ที่คุณเห็นฉันเป็นนักพัฒนา Android (ตอนนี้) และฉันไม่มี idiosyncrasies ที่เกี่ยวข้องกับ J2EE;) ฉันเห็นด้วยแน่นอนว่าการเลือกตั้งชื่อไม่ควรขัดแย้งกัน ด้วยกรอบการทำงานของคุณใช้
Konrad Morawski
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.