ผู้แทนคืออะไร [ปิด]


152

ฉันสับสนว่าบทบาทที่แท้จริงของผู้รับมอบสิทธิ์คืออะไร

ฉันถูกถามคำถามนี้หลายครั้งในการสัมภาษณ์ของฉัน แต่ฉันไม่คิดว่าผู้สัมภาษณ์พอใจกับคำตอบของฉัน

ใครสามารถบอกคำจำกัดความที่ดีที่สุดในหนึ่งประโยคพร้อมตัวอย่างที่ใช้ได้จริง


21
ด้วยความอยากรู้อยากเห็นคุณตอบสนองอะไรเราจึงสามารถบอกคุณได้ว่าคุณจะแก้ไขได้อย่างไร
Anthony Forloney

6
ฉันพบว่ามันน่าสนใจที่คำถามนี้ถูกปิด แต่มี 126 upvotes และ 65 คนทำเครื่องหมายว่าเป็นรายการโปรด ดูเหมือนว่าแม้ว่าจะกว้างเกินไปก็ยังเป็นคำถามที่ดีมาก
รวย

คำตอบ:


171

ฉันชอบคิดว่าผู้รับมอบสิทธิ์เป็น "ตัวชี้ไปยังฟังก์ชัน" สิ่งนี้กลับไปเป็นเวลา C วัน แต่ความคิดยังคงอยู่

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

นี่คือการอ้างอิงสำหรับ C # คุณสามารถดู:

ตัวอย่างเช่นใน C # สมมติว่าเรามีการคำนวณที่เราต้องการทำและเราต้องการใช้วิธีการคำนวณที่แตกต่างซึ่งเราไม่รู้จนกระทั่งถึงรันไทม์ ดังนั้นเราอาจมีวิธีการคำนวณสองสามอย่างดังนี้:

public static double CalcTotalMethod1(double amt)
{
    return amt * .014;
}

public static double CalcTotalMethod2(double amt)
{
    return amt * .056 + 42.43;
}

เราสามารถประกาศลายเซ็นผู้แทนเช่นนี้:

public delegate double calcTotalDelegate(double amt);

จากนั้นเราสามารถประกาศเมธอดที่ใช้ผู้รับมอบสิทธิ์เป็นพารามิเตอร์ดังนี้:

public static double CalcMyTotal(double amt, calcTotalDelegate calcTotal)
{
    return calcTotal(amt);
}

และเราสามารถเรียกCalcMyTotalวิธีการส่งผ่านในวิธีมอบสิทธิ์ที่เราต้องการใช้

double tot1 = CalcMyTotal(100.34, CalcTotalMethod1);
double tot2 = CalcMyTotal(100.34, CalcTotalMethod2);
Console.WriteLine(tot1);
Console.WriteLine(tot2);

19
+1 สำหรับผงกศีรษะไปยังตัวชี้ฟังก์ชันที่เรียบง่าย แต่มีประสิทธิภาพในซี
ไอเดนเบลล์

3
คำถามหนึ่งข้อที่เกี่ยวข้องกับคำตอบของคุณ มันแตกต่างจากการเรียกฟังก์ชั่นตามปกติอย่างไร เพียงเพราะมันไม่รู้จักรันไทม์?
Naveed

1
@NAVEED - อ้างถึงการแก้ไขล่าสุดของฉันฉันรวมตัวอย่าง เท่าที่การเรียกใช้เมธอดจริงมันไม่ได้ดูแตกต่างจากการเรียกใช้เมธอดปกติในตัวอย่างของฉันด้านบน (calcTotal (amt) กำลังเรียกผู้แทน) แต่พลังของผู้ได้รับมอบหมายคือคุณสามารถใช้พวกเขาเป็นพารามิเตอร์ ฯลฯ เมื่อคุณต้องการวิธีการที่จะสามารถมีพฤติกรรมที่แตกต่างกัน ยังมีอีกหลายสิ่งที่คุณสามารถใช้มันได้นี่เป็นเพียงตัวอย่างง่ายๆ หวังว่าจะช่วย
dcp

มันไม่ได้เป็นที่รู้จักกันที่รันไทม์และเป็นฟังก์ชั่นที่ถูกผูกไว้มากกว่าฟังก์ชั่นฟรี - การกำหนดวิธีการที่ไม่คงFooที่จะเป็นผู้รับมอบสิทธิ์จะเรียกthis.Foo()มากกว่าฟังก์ชั่นแบบคงที่เป็นตัวชี้ฟังก์ชันจะทำ (ใน C, คุณมักจะมีเพิ่มvoid*พารามิเตอร์ ส่งผ่านthisไปยังตัวชี้ฟังก์ชัน)
Pete Kirkham

1
+1 สำหรับตัวอย่างที่รวดเร็วและมีประสิทธิภาพการสร้างความคล้ายคลึงกันกับตัวชี้ฟังก์ชันใน C / C ++ ชื่นชมมาก!
G21

19

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

บางรหัสที่จะสาธิต (เขียนสิ่งนี้จากหน่วยความจำดังนั้นไวยากรณ์อาจถูกปิด)

delegate void delMyDelegate(object o);

private void MethodToExecute1(object o)
{
    // do something with object
}

private void MethodToExecute2(object o)
{
    // do something else with object
}

private void DoSomethingToList(delMyDelegate methodToRun)
{
    foreach(object o in myList)
        methodToRun.Invoke(o);
}

public void ApplyMethodsToList()
{
    DoSomethingToList(MethodToExecute1);
    DoSomethingToList(MethodToExecute2);
}

16

ถ่ายจากที่นี่

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

หรือเป็นตัวอย่างหลอกง่าย: มีบางอย่างส่งคำขอไปยัง object1 object1 จากนั้นส่งต่อคำร้องขอและตัวเองไปยัง object2 - ผู้รับมอบสิทธิ์ object2 ประมวลผลคำขอและทำงานได้บางอย่าง (หมายเหตุ: ลิงค์ด้านบนเป็นตัวอย่างที่ดี)


ตัวอย่างที่ระบุในลิงก์ด้านบนไม่ได้ระบุการมอบหมายอย่างถูกต้อง
Hardik9850


4

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

ตัวแทนอย่างง่าย

Declaration of delegate:
delegate-modifier delegate return-type delegate-name(parameters)
Implementation of delegate:
Delegate-name delegate-object=new Delegate-name(method of class)

http://knowpacific.wordpress.com/2012/01/26/delegate/


2

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

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

Delegates are like C++ function pointers but are type safe.
Delegates allow methods to be passed as parameters.
Delegates can be used to define callback methods.
Delegates can be chained together; for example, multiple methods can be called on a single event.
Methods do not have to match the delegate signature exactly.

public delegate type_of_delegate delegate_name () // Declaration

You can use delegates without parameters or with parameter list
If you are referring to the method with some data type then the delegate which you are declaring should be in the same format. This is why it is referred to as type safe function pointer. Here I am giving an example with String.

ตัวอย่างต่อไปนี้แสดงการดำเนินงานของผู้รับมอบสิทธิ์:

    namespace MyDelegate
    {
        class Program
        {
            private delegate void Show(string s);


            // Create a method for a delegate.
            public static void MyDelegateMethod(string me

ssage)
        {
            System.Console.WriteLine(message);
        }

        static void Main(string[] args)
        {
            Show p = MyDelegateMethod;
            p("My Delegate");
            p.Invoke("My Delegate");
            System.Console.ReadLine();
        }
    }
}

Multicast Delegate คืออะไร

มันเป็นตัวแทนที่มีการอ้างอิงมากกว่าหนึ่งวิธี ผู้รับหลายผู้รับจะต้องมีวิธีการที่ส่งกลับเป็นโมฆะอย่างอื่นมีข้อยกเว้นขณะทำงาน

 delegate void MyMulticastDelegate(int i, string s);
 Class Class2
 {
  static void MyFirstDelegateMethod(int i, string s)
  {
    Console.WriteLine("My First Method");
  }

  static void MySecondDelegateMethod(int i, string s)
  {
    Console.WriteLine("My Second Method");
  }

  static void Main(string[] args)
  {
    MyMulticastDelegate Method= new MyMulticastDelegate(MyFirstDelegateMethod);
    Method+= new MyMulticastDelegate (MySecondDelegateMethod);
    Method(1,"Hi");             // Calling 2 Methodscalled
    Method-= new MyMulticastDelegate (MyFirstDelegateMethod);
    Method(2,"Hi");             //Only 2nd Method calling
  }
}

ผู้เข้าร่วมที่นี่จะถูกเพิ่มโดยใช้ตัวดำเนินการ + = และนำออกโดยใช้ตัวดำเนินการ - =

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


1

คำอธิบายที่ดีและการใช้งานจริงของรูปแบบผู้ได้รับมอบหมายสามารถพบได้ใน Google Collections Classing Forwarding Classes (เช่นเดียวกับรูปแบบมัณฑนากร)


1

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

button1.Click + = new System.EventHandler (button1_Click) System.EventHandler ได้รับการประกาศให้เป็นผู้แทนที่นี่ใน. net กิจกรรมทำงานบนแนวคิดของ Delegate (เช่น Button Click)

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

http://msdn.microsoft.com/en-us/library/ms173171(v=vs.80).aspx


1

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


1

ผู้รับมอบสิทธิ์เป็นวัตถุที่แสดงถึงตัวชี้ไปยังฟังก์ชัน อย่างไรก็ตามมันไม่ได้เป็นตัวชี้ฟังก์ชั่นสามัญที่:

1) เป็นวัตถุที่มุ่งเน้น

2) เป็นประเภทที่ปลอดภัยหรือไม่นั่นคือสามารถชี้ไปที่วิธีการหนึ่งเท่านั้นและคุณไม่สามารถอ่านที่อยู่หน่วยความจำดิบที่ชี้ไปได้

3) พิมพ์อย่างยิ่ง มันสามารถชี้ไปที่วิธีการที่ตรงกับลายเซ็นของมัน

4) สามารถชี้ไปที่มากกว่าหนึ่งวิธีในเวลาเดียวกัน


1

ผู้รับมอบสิทธิ์ส่วนใหญ่จะใช้กับกิจกรรม

ความต้องการคือ:

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

ตัวอย่าง:

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

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

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


0

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

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

ตัวอย่างง่ายๆ:

SomeInterface
{
   public void doSomething();
}


SomeImplementation implements SomeInterface
{
   public void doSomething()
   {
      System.err.println("Was it good for you?");
   }

}


SomeCaller
{
   public void doIt(SomeInterface someInterface)
   {
      someInterface.doSomething();
   }
}

ตอนนี้คุณเห็นว่าฉันสามารถใช้การติดตั้งแบบใดก็ได้ที่ต้องการได้ตลอดเวลาโดยไม่ต้องเปลี่ยนรหัสใน SomeCaller เพราะประเภทที่doIt()ส่งผ่านนั้นไม่เป็นรูปธรรม แต่ค่อนข้างเป็นนามธรรมเนื่องจากเป็นส่วนต่อประสาน ในโลกของ Java สิ่งนี้มักจะแสดงออกมาในกระบวนทัศน์การบริการที่คุณเรียกใช้บริการ (วัตถุโฆษณาด้วยตัวเองเป็นบริการผ่านอินเทอร์เฟซเฉพาะ) และบริการจากนั้นจะโทรออกไปยังผู้รับมอบสิทธิ์เพื่อช่วยในการทำงาน เมธอดของเซอร์วิสถูกตั้งชื่อเป็นงานที่หยาบ (makePayment (), createNewUser (), ฯลฯ ) ในขณะที่ภายในจะมีจำนวนมากหาก nitty-gritty ทำงานผ่านการมอบหมายโดยชนิดของผู้ได้รับมอบหมายแทนการใช้งานที่เป็นรูปธรรม

SomeService
{
    SomeInterface someImplementation = ... // assign here
    SomeOtherInterface someOtherImplementation = ... // okay, let's add a second

    public void doSomeWork()
    {
         someImplementation.doSomething();
         someOtherImplementation.doSomethingElse();
    }
}

(NB: วิธีการใช้งานที่ได้รับมอบหมายนั้นอยู่นอกเหนือขอบเขตของเธรดนี้การค้นหาผกผันของการควบคุมและการฉีดพึ่งพา)


-2

แม้ว่าจะไม่ใช่ "ตัวชี้ฟังก์ชัน" จริงๆผู้รับมอบสิทธิ์อาจมีลักษณะเช่นนี้เป็นภาษาแบบไดนามิกเช่น PHP:



$func = 'foo';
$func();

function foo() {
    print 'foo';
}

หรือใน JavaScript คุณสามารถทำสิ่งที่ชอบ:


var func = function(){ alert('foo!'); }
func();


2
นี่ไม่ใช่ตัวอย่างของการมอบหมาย ในตัวอย่างของคุณคุณกำลังใช้สิ่งที่เรียกว่าฟังก์ชั่นตัวแปรซึ่งโดยทั่วไปจะมองหาฟังก์ชั่นที่มีชื่อเดียวกันกับสตริงที่ตัวแปรอ้างอิง ดูฟังก์ชั่นตัวแปร: php.net/manual/en/functions.variable-functions.php
Aquarelle
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.