ผู้แทน Java


194

ภาษา Java มีคุณสมบัติของผู้ร่วมประชุมคล้ายกับที่ C # มีการสนับสนุนสำหรับผู้ได้รับมอบหมายหรือไม่?


20
@Suma สิ่งนี้จะซ้ำกันได้อย่างไรหากคำถามที่คุณพูดถึงถูกโพสต์หลังจากหนึ่งปีนี้?
Ani

1
Java 8 มีคุณสมบัติเหมือนผู้ได้รับมอบหมาย มันถูกเรียกว่า lambdas
tbodt

4
@tbodt ให้ถูกต้องมากขึ้นJava 8 มีคุณสมบัติเหมือนผู้ได้รับมอบหมาย มันเรียกว่าอินเตอร์เฟซที่ใช้งานได้ Lambdas เป็นวิธีหนึ่งในการสร้างอินสแตนซ์ของผู้ร่วมประชุม (โดยไม่ระบุชื่อ)
nawfal

3
คำตอบด้านล่างมาจาก Pre-Java 8 โพสต์ Java 8 ดูคำตอบในหัวข้อนี้: stackoverflow.com/questions/20311779/…
Michael Lloyd Lee mlk

@nawfal, +1, แต่เพื่อให้ถูกต้องมากขึ้น, Java 7 และต่ำกว่ามีคุณสมบัติเหมือนผู้ได้รับมอบหมาย มันเรียกว่าอินเตอร์เฟซธรรมดา
Pacerier

คำตอบ:


152

ไม่จริงไม่

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

คุณอาจพบว่าบทความนี้น่าสนใจ / มีประโยชน์: โปรแกรมเมอร์ Java ดูที่ C # Delegates (@ archive.org)


3
การแก้ปัญหาด้วย invoke () เป็นฟังก์ชั่นสมาชิกเท่านั้นของอินเทอร์เฟซที่ดีจริงๆ
Stephane Rolland

1
แต่ดูตัวอย่างของฉันที่นี่ในสิ่งที่จะทำแม้แต่ใน Java 7 เพื่อบรรลุเทียบเท่ากับตัวแทน C #
ToolmakerSteve

63

ขึ้นอยู่กับสิ่งที่คุณหมายถึงคุณสามารถบรรลุผลที่คล้ายกัน (ผ่านวิธีการ) โดยใช้รูปแบบกลยุทธ์

แทนที่จะเป็นบรรทัดเช่นนี้ประกาศลายเซ็นวิธีการที่มีชื่อ:

// C#
public delegate void SomeFunction();

ประกาศอินเตอร์เฟส:

// Java
public interface ISomeBehaviour {
   void SomeFunction();
}

สำหรับการประยุกต์ใช้วิธีที่เป็นรูปธรรมให้กำหนดคลาสที่ใช้ลักษณะการทำงาน:

// Java
public class TypeABehaviour implements ISomeBehaviour {
   public void SomeFunction() {
      // TypeA behaviour
   }
}

public class TypeBBehaviour implements ISomeBehaviour {
   public void SomeFunction() {
      // TypeB behaviour
   }
}

เมื่อใดก็ตามที่คุณมีSomeFunctionตัวแทนใน C # ให้ใช้การISomeBehaviourอ้างอิงแทน:

// C#
SomeFunction doSomething = SomeMethod;
doSomething();
doSomething = SomeOtherMethod;
doSomething();

// Java
ISomeBehaviour someBehaviour = new TypeABehaviour();
someBehaviour.SomeFunction();
someBehaviour = new TypeBBehaviour();
someBehaviour.SomeFunction();

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

// Java
public void SomeMethod(ISomeBehaviour pSomeBehaviour) {
   ...
}

...

SomeMethod(new ISomeBehaviour() { 
   @Override
   public void SomeFunction() {
      // your implementation
   }
});

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

และแน่นอนใน Java 8 สิ่งเหล่านี้จะกลายเป็นการแสดงออกแลมบ์ดาโดยทั่วไป:

// Java 8
SomeMethod(() -> { /* your implementation */ });

6
+1 นี่เป็นวิธีการแก้ปัญหาที่เหมาะสมและความฟุ่มเฟื่อยอาจชดเชยด้วยการบำรุงรักษาในอนาคต
nawfal

นี่ยอดเยี่ยม ... กำลังทำงานในโครงการที่ฉันไม่สามารถใช้การสะท้อนเนื่องจากข้อ จำกัด ของโครงการและวิธีแก้ปัญหานี้ทำให้งานเสร็จอย่างสวยงาม :)
Jonathan Camarena

Java มีหลักการตั้งชื่อ I-prefix สำหรับอินเตอร์เฟสหรือไม่ ฉันไม่เคยเห็นแบบนั้นมาก่อน
Kyle Delaney

36

เรื่องย่อ: ไม่มี

บทนำ

รุ่นใหม่ล่าสุดของ J การพัฒนาสภาพแวดล้อม Microsoft Visual ++ สนับสนุนภาษาสร้างเรียกว่าได้รับมอบหมายหรืออ้างอิงวิธีการที่ถูกผูกไว้ โครงสร้างนี้และคำหลักใหม่delegateและ multicastนำไปสนับสนุนมันไม่ได้เป็นส่วนหนึ่งของจาวาTM ภาษาการเขียนโปรแกรมซึ่งระบุโดยJava Language ข้อกำหนดและแก้ไขเพิ่มเติมโดยคลาสจำเพาะรวมอยู่ในเอกสารสำหรับซอฟต์แวร์ JDKTM 1.1

ไม่น่าเป็นไปได้ที่ภาษาการเขียนโปรแกรม Java จะรวมโครงสร้างนี้ ซันได้พิจารณาอย่างรอบคอบแล้วว่าได้ยอมรับมันในปี 1996 จนถึงระดับของการสร้างและทิ้งต้นแบบการทำงาน ข้อสรุปของเราคือการอ้างอิงวิธีการผูกไว้ไม่จำเป็นและเป็นอันตรายต่อภาษา การตัดสินใจครั้งนี้ทำขึ้นโดยการปรึกษาหารือกับ Borland International ซึ่งเคยมีประสบการณ์มาก่อนด้วยการอ้างอิงวิธีการที่ถูกผูกมัดใน Delphi Object Pascal

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

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


อย่างที่บอกไว้ในสิ่งที่Patrick เชื่อมโยงคุณต้องการใช้คลาสภายในแทน
SCdF

16
บทความดีๆ ฉันชอบความหมายของคำว่า "ง่าย": Java เป็นภาษาที่ได้รับการออกแบบให้เรียบง่ายเหมือนใน "Java จะต้องเรียบง่ายในการเขียนคอมไพเลอร์ / VM สำหรับ" ในขณะที่ละเว้น "Java จะต้องง่ายต่อการเขียน / อ่านโดยบุคคล" . อธิบายได้มากมาย
Juozas Kontvainis

5
ฉันแค่คิดว่าซันทำผิดพลาดครั้งใหญ่ พวกเขาไม่ได้เชื่อมั่นในกระบวนทัศน์การทำงานและนั่นคือทั้งหมด
Stephane Rolland

7
@Juozas: งูหลามทำ explicitely ให้ง่ายต่อการเขียน / อ่านโดยบุคคลและมันจะนำไปปฏิบัติแลมบ์ดาฟังก์ชั่น / ผู้ได้รับมอบหมาย
Stephane Rolland

5
แทนที่ด้วยลิงก์ archive.org นอกจากนี้ยังเป็นสิ่งที่โง่จริงๆ Oracle
Patrick

18

คุณได้อ่านสิ่งนี้ :

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

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

obj.registerHandler (ano.methodOne);

.. และว่าวิธีการวิธีหนึ่งจะถูกเรียกว่า ano เมื่อได้รับเหตุการณ์เฉพาะบางอย่าง

นี่คือความสำเร็จของโครงสร้างผู้ได้รับมอบหมาย

Java Inner Classes

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

obj.registerHandler(new Handler() {
        public void handleIt(Event ev) {
            methodOne(ev);
        }
      } );

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

ผู้จัดการทั่วไป

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

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

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

void processState(final T1 p1, final T2 dispatch) { 
  final int a1 = someCalculation();

  m_obj.registerHandler(new Handler() {
    public void handleIt(Event ev) {
     dispatch.methodOne(a1, ev, p1);
    }
  } );
}

สุดท้าย * สุดท้าย * สุดท้าย

ได้รับความสนใจของคุณ?

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

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


13

ฉันรู้ว่าโพสต์นี้เก่า แต่ Java 8 ได้เพิ่มแลมบ์ดาและแนวคิดของส่วนต่อประสานการทำงานซึ่งเป็นส่วนต่อประสานใด ๆ ที่มีเพียงวิธีเดียว ร่วมกันนำเสนอฟังก์ชั่นที่คล้ายกันกับตัวแทน C # ดูที่นี่สำหรับข้อมูลเพิ่มเติมหรือเพียงแค่ Google Java Lambdas http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html


5

ไม่ แต่พวกเขาปลอมแปลงโดยใช้พร็อกซีและการสะท้อนภาพ:

  public static class TestClass {
      public String knockKnock() {
          return "who's there?";
      }
  }

  private final TestClass testInstance = new TestClass();

  @Test public void
  can_delegate_a_single_method_interface_to_an_instance() throws Exception {
      Delegator<TestClass, Callable<String>> knockKnockDelegator = Delegator.ofMethod("knockKnock")
                                                                   .of(TestClass.class)
                                                                   .to(Callable.class);
      Callable<String> callable = knockKnockDelegator.delegateTo(testInstance);
      assertThat(callable.call(), is("who's there?"));
  }

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

ดูรหัส karg บน githubสำหรับการทดสอบและการใช้งานเพิ่มเติม


2

ฉันใช้งานการสนับสนุนการโทรกลับ / ผู้รับมอบสิทธิ์ใน Java โดยใช้การสะท้อนกลับ รายละเอียดและแหล่งที่มาทำงานอยู่ที่มีอยู่บนเว็บไซต์ของฉัน

มันทำงานอย่างไร

มีคลาสหลักการชื่อ Callback ที่มีคลาสซ้อนกันชื่อ WithParms API ที่ต้องการการเรียกกลับจะใช้วัตถุโทรกลับเป็นพารามิเตอร์และถ้าจำเป็นให้สร้าง Callback.WithParms เป็นตัวแปรวิธี เนื่องจากแอพพลิเคชั่นมากมายของวัตถุนี้จะถูกเรียกซ้ำการทำงานนี้อย่างหมดจด

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

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

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

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

static private final Method             COUNT =Callback.getMethod(Xxx.class,"callback_count",true,File.class,File.class);

...

IoUtil.processDirectory(root,new Callback(this,COUNT),selector);

...

private void callback_count(File dir, File fil) {
    if(fil!=null) {                                                                             // file is null for processing a directory
        fileTotal++;
        if(fil.length()>fileSizeLimit) {
            throw new Abort("Failed","File size exceeds maximum of "+TextUtil.formatNumber(fileSizeLimit)+" bytes: "+fil);
            }
        }
    progress("Counting",dir,fileTotal);
    }

IoUtil.processDirectory ():

/**
 * Process a directory using callbacks.  To interrupt, the callback must throw an (unchecked) exception.
 * Subdirectories are processed only if the selector is null or selects the directories, and are done
 * after the files in any given directory.  When the callback is invoked for a directory, the file
 * argument is null;
 * <p>
 * The callback signature is:
 * <pre>    void callback(File dir, File ent);</pre>
 * <p>
 * @return          The number of files processed.
 */
static public int processDirectory(File dir, Callback cbk, FileSelector sel) {
    return _processDirectory(dir,new Callback.WithParms(cbk,2),sel);
    }

static private int _processDirectory(File dir, Callback.WithParms cbk, FileSelector sel) {
    int                                 cnt=0;

    if(!dir.isDirectory()) {
        if(sel==null || sel.accept(dir)) { cbk.invoke(dir.getParent(),dir); cnt++; }
        }
    else {
        cbk.invoke(dir,(Object[])null);

        File[] lst=(sel==null ? dir.listFiles() : dir.listFiles(sel));
        if(lst!=null) {
            for(int xa=0; xa<lst.length; xa++) {
                File ent=lst[xa];
                if(!ent.isDirectory()) {
                    cbk.invoke(dir,ent);
                    lst[xa]=null;
                    cnt++;
                    }
                }
            for(int xa=0; xa<lst.length; xa++) {
                File ent=lst[xa];
                if(ent!=null) { cnt+=_processDirectory(ent,cbk,sel); }
                }
            }
        }
    return cnt;
    }

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

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


1

ใช่ & ไม่ใช่ แต่รูปแบบของผู้ได้รับมอบอำนาจใน Java อาจจะเป็นอย่างนี้ วิดีโอการสอนนี้เกี่ยวกับการแลกเปลี่ยนข้อมูลระหว่างกิจกรรม - ชิ้นส่วนและมีสาระสำคัญของรูปแบบการมอบหมายผู้แทนโดยใช้ส่วนต่อประสาน

Java Interface


1

ไม่มีdelegateคำหลักที่ชัดเจนว่า C # แต่คุณสามารถบรรลุคล้ายกันใน Java 8 โดยใช้อินเตอร์เฟซที่ใช้งานได้ (เช่นอินเทอร์เฟซที่มีวิธีการเดียว) และแลมบ์ดา:

private interface SingleFunc {
    void printMe();
}

public static void main(String[] args) {
    SingleFunc sf = () -> {
        System.out.println("Hello, I am a simple single func.");
    };
    SingleFunc sfComplex = () -> {
        System.out.println("Hello, I am a COMPLEX single func.");
    };
    delegate(sf);
    delegate(sfComplex);
}

private static void delegate(SingleFunc f) {
    f.printMe();
}

วัตถุประเภทใหม่ทุกประเภทSingleFuncจะต้องนำมาใช้printMe()ดังนั้นจึงปลอดภัยที่จะส่งต่อไปยังวิธีอื่น (เช่นdelegate(SingleFunc)) เพื่อเรียกprintMe()วิธีการนั้น


0

ในขณะที่มันอยู่ตรงไหนเกือบเป็นสะอาด แต่คุณสามารถใช้สิ่งที่ได้รับมอบหมายเช่น C # ใช้ Java พร็อกซี่


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

2
@ StackFlowed ดึงลิงค์แล้วคุณจะได้อะไร โพสต์ที่มีข้อมูล โหวตให้
Scimonster

1
@Sconster จะเกิดอะไรขึ้นหากลิงก์ไม่ถูกต้องอีกต่อไป
StackFlowed

@StackFlowed มันยังคงให้คำตอบ - ใช้ Java Proxy
Scimonster

ถ้าเป็นความคิดเห็นล่ะก็?
StackFlowed

0

ไม่ แต่มันมีพฤติกรรมที่คล้ายกันภายใน

ในผู้รับมอบสิทธิ์ C # จะใช้ในการสร้างจุดเข้าใช้งานแยกจากกันและทำงานเหมือนกับตัวชี้ฟังก์ชัน

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

ตัวอย่างเช่นการสร้างเธรดใน Java ต้องการคลาสที่ขยายเธรดหรือใช้งาน Runnable เนื่องจากตัวแปรคลาสอ็อบเจ็กต์สามารถใช้เป็นตัวชี้ตำแหน่งหน่วยความจำได้



0

รหัสที่อธิบายมีข้อได้เปรียบหลายอย่างของผู้ได้รับมอบหมาย C # วิธีการทั้งแบบคงที่หรือแบบไดนามิกสามารถได้รับการปฏิบัติในลักษณะที่สม่ำเสมอ ความซับซ้อนในวิธีการโทรผ่านการสะท้อนกลับลดลงและรหัสนี้สามารถนำมาใช้ซ้ำได้โดยไม่จำเป็นต้องมีคลาสเพิ่มเติมในรหัสผู้ใช้ หมายเหตุเรากำลังเรียกใช้เวอร์ชันที่สะดวกสบายอื่น ๆ ของ invoke โดยที่สามารถเรียกเมธอดที่มีพารามิเตอร์หนึ่งตัวได้โดยไม่ต้องสร้าง object array รหัส Java ด้านล่าง:

  class Class1 {
        public void show(String s) { System.out.println(s); }
    }

    class Class2 {
        public void display(String s) { System.out.println(s); }
    }

    // allows static method as well
    class Class3 {
        public static void staticDisplay(String s) { System.out.println(s); }
    }

    public class TestDelegate  {
        public static final Class[] OUTPUT_ARGS = { String.class };
        public final Delegator DO_SHOW = new Delegator(OUTPUT_ARGS,Void.TYPE);

        public void main(String[] args)  {
            Delegate[] items = new Delegate[3];

            items[0] = DO_SHOW .build(new Class1(),"show,);
            items[1] = DO_SHOW.build (new Class2(),"display");
            items[2] = DO_SHOW.build(Class3.class, "staticDisplay");

            for(int i = 0; i < items.length; i++) {
                items[i].invoke("Hello World");
            }
        }
    }

-11

Java ไม่มีตัวแทนและภูมิใจในมัน :) จากสิ่งที่ฉันอ่านที่นี่ฉันพบในสาระสำคัญ 2 วิธีในการปลอมตัวแทน: 1. การสะท้อนกลับ; 2. ชั้นใน

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


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