tutorials.de Buch-Aktion 05/2012
ERLEDIGT
JA
ANTWORTEN
6
ZUGRIFFE
731
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Avatar von Muepe32
    Muepe32 Muepe32 ist offline Mitglied Brokat
    Registriert seit
    Mar 2011
    Beiträge
    353
    Hallo zusammen,

    Wie ich im Netz lesen konnte ist es in Java momentan nicht möglich Funktionszeiger zu verwenden. Da ich bis vor wenigen Tagen noch praktisch nur in C# programmiert habe ist das natürlich für mich ein ziemlich grosser Schock, da mit anonymen Delegaten und anderem das Konzept der Funktionszeiger in C# sozusagen auf die Spitze getrieben wurde und ich dies auch gerne verwende.

    Nun habe ich mich also gefragt was es denn für gute Alternativen gäbe. Als Beispiel habe ich folgende Situation:
    Code java:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    class LogonClient {
        protected void handleLogonInit(byte[] data) {
        }
        
        protected void handleLogonProof(byte[] data) {
        }
        
        @Override
        protected void OnDataReceived(byte[] data) {
            if(data == null || data.length == 0)
                return;
            
            int opcode = data[0];
        }
    }

    Während sich hier das ganze noch relativ in Grenzen hält und über einen switch oder ein if realisierbar ist (opcode 0 -> handleLogonInit, opcode 1 -> handleLogonProof) ist es natürlich verständlich, dass in späteren Stadien meines Protokolls viel mehr hinzukommen wird. Ich würde jetzt eigentlich gerne eine assoziative Verbindung opcode -> Handlerfunktion machen.

    Ich habe mal eine Variante mit anonymer Klasse gemacht, diese ist aber vom Schreibaufwand her auch nicht gerade schonend
    Code java:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    class LogonClient {
        private static HashMap<Integer, IPacketFunction> mPacketFunctions;
        
        private interface IPacketFunction {
            public void execute(byte[] data, LogonClient client);
        }
     
        static {
            mPacketFunctions = new HashMap<Integer, IPacketFunction>();
            mPacketFunctions.put(0, new IPacketFunction() { public void execute(byte[] data, LogonClient client) { client.handleLogonInit(data); } });
        }
    }

    Gibt es da noch kürzere oder elegantere Versionen?

    Grüsse
    Muepe
     
    Viele Tutorials und Artikel zur Programmierung unter Windows mit C++ und C#. Tägliche Updates und Antworten auf eure Fragen:
    Win32Easy - Blog
    Es würde mich freuen, wenn ihr einen Kommentar postet!

  2. #2
    genodeftest genodeftest ist offline Mitglied Brillant
    Registriert seit
    Jun 2009
    Beiträge
    870
    Hab ich das richtig verstanden (zum 1. Codebeispiel):
    Du willst Daten mit der Methode OnDataReceived() empfangen und je nach Inhalt des Parameters (byte[]) entweder handleLogonInit() oder handleLogonProof() aufrufen.

    Dafür ist doch eine if-Abfrage bzw. ein switch-Block gedacht, warum nicht?
     
    Code bitte so einfügen: [java]System.out.println("Hallo");[/java] (Analog für andere Programmiersprachen)
    Code java:
    1
    
    System.out.println("Hallo");
    hilfreich zu Java: Really Big Index, Java ist auch eine Insel Band 1 und Band 2.
    ___________
    Ubuntu Bug #1: Microsoft has a majority market share
    Casecon: Projekt leiser Käse

  3. #3
    SE Tutorials.de Gastzugang
    Ich denke eher das TO das so änlich wie mit Reflections machen will das er dierekt per String angeben kann welche Methode zu verweden ist ... ansonsten verstehe ich so gut wie nichts aus dem Post da ich mich weder mit C noch dem geschildertem Problem auskenne ...
     

  4. #4
    Avatar von Muepe32
    Muepe32 Muepe32 ist offline Mitglied Brokat
    Registriert seit
    Mar 2011
    Beiträge
    353
    Hallo genodeftest,

    Dazu habe ich in meinem Posting auch was geschrieben:
    Zitat Zitat von Muepe32 Beitrag anzeigen
    Während sich hier das ganze noch relativ in Grenzen hält und über einen switch oder ein if realisierbar ist (opcode 0 -> handleLogonInit, opcode 1 -> handleLogonProof) ist es natürlich verständlich, dass in späteren Stadien meines Protokolls viel mehr hinzukommen wird.
    Mit "viel mehr" meine ich Sachen wie 1500 verschiedene Opcodes mit entsprechend ungefähr 1000 Handlern. Da alles mit switches bzw. if-Abfragen zu machen ist viel zu aufwändig.

    In C# zum Beispiel habe ich ein Enum für alle Opcodes und kann folgenden Ansatz verwenden:
    Code csharp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    
    enum Opcodes
    {
       MSG_LOGON_INIT,
       MSG_LOGON_PROOF,
    }
     
    public class LogonClient
    {
       public void OnDataReceived(byte[] data)
       {
          int opcode = data[0];
          if(mPacketHandlers.ContainsKey(opcode))
          {
             var method = mPacketHandlers[opcode];
             if(method != null)
                method.Invoke(this, data);
          }         
       }
     
       public void Handle_MSG_LOGON_INIT(byte[] data)
       {
       }
     
       public void Handle_MSG_LOGON_PROOF(byte[] data)
       {
       }
     
       private static Dictionary<int, MethodInfo> mPacketHandlers = new Dictionary<int, MethodInfo>();
     
       static LogonClient()
       {
          var values = Enum.GetValues(typeof(Opcodes));
          var handler = typeof(LogonClient);
     
          foreach(var value in values)
          {
             var method = "Handle_" + value.ToString();
             var info = handler.GetMethod(method);
             if(info != null)
                mPacketHandlers.Add((Opcodes)value, info);
          }
       }
    }

    Dadurch kann ich beliebig Opcodes hinzufügen und entfernen und habe dadurch keinen zusätzlichen Schreibaufwand mehr. Ist eine von vielen Möglichkeiten wie man das realisieren kann. Sämtliche Informationen werden erst zu Laufzeit zusammengestellt.

    So etwas ähnliches möchte ich auch Java machen.

    Gruss
    Muepe
     
    Viele Tutorials und Artikel zur Programmierung unter Windows mit C++ und C#. Tägliche Updates und Antworten auf eure Fragen:
    Win32Easy - Blog
    Es würde mich freuen, wenn ihr einen Kommentar postet!

  5. #5
    SE Tutorials.de Gastzugang
    Ja ... sowas geht auch ganz gut in Java ... allerdings nur mit den sog. Reflections was eigentlich ein nicht so gutes Design ist aber für dynamischen Code das Mittel der Wahl ist.

    Du kannst die via Class.getDelclearedMethodes() ein Array geben lassen das alle in dieser Klasse deklarierten Methoden enthält *wenn du alle willst verwende stattdessen Class.getMethodes()*.
    Nun kannst du dir mit Methode.getName() den Methoden-Namen geben lassen ... diesen dann mit String.equals(String) vergleichen und dann fast genau so wie in deinem C-Code mittels invoke aufrufen.
    Du kannst auch dierekt Methoden-Namen konstruieren ... dies meldet der Compiler aber dann mit einer UNCHECKED-WARNING ... was einfach nur aufzeigen soll das der Code leicht zum Crach gebracht werden kann wenn etwas nicht wirklich so ist wie du es zur Compile-Zeit angenommen hast. Daher ist es sicherer sich die Methoden als Array zu holen und diese abzugleichen. Dadurch hast du bei Fehlern ein etwas besseres Error-Handling weil du nicht umständlich Exceptions abfangen und parsen musst sondern dierekt mit den übergebenen Werten arbeiten kannst.

    Ich habe grade leider keinen Link zu Reflections parat .. aber google sollte dir da einiges liefern.
     

  6. #6
    Avatar von Muepe32
    Muepe32 Muepe32 ist offline Mitglied Brokat
    Registriert seit
    Mar 2011
    Beiträge
    353
    Als ich das Beispiel oben schrieb habe ich auch gemerkt, dass ich ja gar keine Delegate/Funktionszeiger mehr benötige sondern alles über Reflection geregelt habe und das ja in Java auch möglich sein müsste. Mit deinen Hinweisen noch dazu habe ich das dann folgendermassen implementiert:
    Code java:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
        private static HashMap<Integer, Method> mPacketMethods;
     
        static {
            mPacketMethods = new HashMap<Integer, Method>();
            Class<LogonClient> cls = LogonClient.class;
            Opcodes[] values = Opcodes.class.getEnumConstants();
     
            for(Opcodes opcode : values) {
                String name = "handle_" + opcode.toString();
                try {
                    Method m = cls.getDeclaredMethod(name, byte[].class);
                    mPacketMethods.put(opcode.getOpcode(), m);
                } catch (NoSuchMethodException e) {
                    System.out.println("The opcode '" + opcode.toString() + "' has no handler!");
                    continue;
                }
            }
        }
     
    Viele Tutorials und Artikel zur Programmierung unter Windows mit C++ und C#. Tägliche Updates und Antworten auf eure Fragen:
    Win32Easy - Blog
    Es würde mich freuen, wenn ihr einen Kommentar postet!

  7. #7
    SE Tutorials.de Gastzugang
    Du könntest das foreach noch um drehen in dem du
    Code java:
    1
    
    for(Methode method : cls.getDeclaredMethods())
    schreiben würdest und dann mit
    Code java:
    1
    
    if(methode.getName().equals("handle_"+opcode.toString()))
    oder sowas auf Vorhandensein der Methode prüfst. Wäre im Prinzip nichts anderes als der try-catch-Block ... würde aber etwas eleganter aussehen.
     

Ähnliche Themen

  1. Alternative zu if-else
    Von Conners im Forum Java Grundlagen
    Antworten: 8
    Letzter Beitrag: 30.10.08, 08:22
  2. Alternative zu GET?
    Von Vertigo21 im Forum PHP
    Antworten: 5
    Letzter Beitrag: 09.06.06, 19:15
  3. Alternative zu <br /> ?
    Von Boof im Forum HTML & XHTML
    Antworten: 3
    Letzter Beitrag: 07.06.06, 13:51
  4. Antworten: 3
    Letzter Beitrag: 23.12.04, 20:22
  5. Alternative pdf.ocx
    Von _tYze im Forum Visual Basic 6.0
    Antworten: 0
    Letzter Beitrag: 16.09.04, 09:35