Frage

Ich habe versucht, einen Weg, um herauszufinden, mehrere Methoden aus meiner Basisklasse zu markieren, so dass eine Client-Klasse sie vom Tag nennen. Der Beispielcode ist:

public class Base {
         public void method1(){     
        ..change state of base class
    }

    public void method2(){      
        ..change state of base class
    }

    public void method3(){      
        ..change state of base class
    }
}

Eine Client-Klasse aus einer main () Methode wird jede Methode der Basis über einen Zufallsbefehlsfolge nennen:

public static void main(String[] args) {
String sequence = "ABCAABBBABACCACC"
Base aBase = new Base();
for (int i = 0; i < sequence.length(); i++){
            char temp = sequence.charAt(i);
            switch(temp){
            case 'A':{aBase.method1(); break;}
            case 'B':{aBase.method2(); break;}
            case 'C':{aBase.method3(); break;}          }
        }

        System.out.println(aBase.getState());

    }

Nun wünsche ich die switch-Anweisung aus dem Client-Objekt ganz loszuwerden. Ich bin die Technik bewusst Schalter durch Polymorphismus zu ersetzen, sondern möchte vermeiden eine Reihe von neuen Klassen zu schaffen. Ich habe gehofft, diese Methoden in einer geeigneten Datenstruktur einfach zu speichern und sie irgendwie mit einem entsprechenden Zeichen aus der Sequenz-Tag.

könnte eine Karte ganz einfach speichern Objekte mit dem Wert / Schlüsselpaare, die den Job machen könnte, (wie ich hier ) oder das Befehlsmuster, aber da will ich nicht diese Methoden mit Objekten ersetzen, gibt es eine andere Art und Weise vielleicht, Methoden zu speichern und einen Client selektiv haben rufen sie?

Jede Beratung wird geschätzt

War es hilfreich?

Lösung

So etwas wie das?

public class Base {

    private final Map<Character, Method> methods = new HashMap<Character, Method>();

    public Base() throws SecurityException, NoSuchMethodException {
        methods.put('A', getClass().getMethod("method1"));
        methods.put('B', getClass().getMethod("method2"));
        methods.put('C', getClass().getMethod("method3"));
    }

    public Method getMethod(char c) {
        return methods.get(c);
    }

    public void method1() {}

    public void method2() {}

    public void method3() {}

}

und dann

    public static void main(String[] args) throws Exception {
        String sequence = "ABCAABBBABACCACC";
        Base aBase = new Base();

        for (int i = 0; i < sequence.length(); i++) {
            char temp = sequence.charAt(i);
            aBase.getMethod(temp).invoke(aBase);
        }
    }

Andere Tipps

Ich würde verwenden Anmerkungen zu den Methoden in Frage, so dass es als „getaggt Methode“ gekennzeichnet werden, und die Bereitstellung des Tag-String für diese Methode zu verwenden.

Von diesem Punkt wird die Umsetzung einfacher; Sie können Reflexion iterieren eine Klasse Methoden und ihre Anmerkungen zu überprüfen; vielleicht ist dies statisch beim Start tun und eine Zuordnung von Tag-String zu Methode von java.lang.reflect füllen.

Dann, wenn die Befehlsfolge der Verarbeitung, rufen die Methoden, die jedes Etikett entsprechen.

Edit: einige Beispielcode:

import java.lang.annotation.*; 

@Retention(RetentionPolicy.RUNTIME)
@interface TaggedMethod {
    String tag();
}

Dann in der Basisklasse:

public class Base {

   @TaggedMethod(tag = "A")
   public void method1(){         
    ..change state of base class
   }

   @TaggedMethod(tag = "B")
   public void method2(){              
    ..change state of base class
   }

   @TaggedMethod(tag = "C")
   public void method3(){              
    ..change state of base class
   }
}

... und im Client:

private static final Map<String, Method> taggedMethods = new HashMap<String, Method>();

// Set up the tag mapping
static
{
   for (Method m : Base.class.getDeclaredMethods())
   {
      TaggedMethod annotation = m.getAnnotation(TaggedMethod.class)
      if (annotation != null)
      {
         taggedMethods.put(annotation.tag(), m);
      }
   }
}

, so dass Sie diese zugreifen, wie:

public static void main(String[] args) throws Exception
{
   String sequence = "ABCAABBBABACCACC"
   Base aBase = new Base();
   for (int i = 0; i < sequence.length(); i++)
   {
            String temp = sequence.substring(i,1);
            Method method = taggedMethods.get(temp);
            if (method != null)
            {
                // Error handling of invocation exceptions not included
                method.invoke(aBase);
            }
            else
            {
               // Unrecognised tag - handle however
            }
    }

    System.out.println(aBase.getState());

}

Dieser Code kompiliert oder nicht getestet, übrigens ...: -)

Sie können Attribute für diese, in C #. Für Java verwenden Anmerkungen. Leiten Sie eine Klasse von der Attributklasse, sagen, TagAttribute, und wenden Sie das Attribut auf die Methoden.

[global::System.AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public sealed class TagAttribute : Attribute
{
    public TagAttribute(char value)
    {
        this.value = value;
    }

    private char value;
    public char Value
    {
        get { return value; }
    }
}

Wenden Sie das Attribut auf die Methoden:

public class MyClass
{
    [Tag('A')]
    public void Method1()
    { Console.Write("a"); }

    [Tag('B')]
    public void Method2()
    { Console.Write("b"); }

    [Tag('C')]
    public void Method3()
    { Console.Write("c"); }
}

Rufen Sie die Methoden Reflexion mit:

private static void CallTaggedMethod(MyClass instance, char value)
{
    MethodInfo methodToCall = null;

    // From the MyClass type...
    Type t = typeof(MyClass);
    // ...get all methods.
    MethodInfo[] methods = t.GetMethods();
    // For each method...
    foreach (MethodInfo mi in methods)
    {
        // ...find all TagAttributes applied to it.
        TagAttribute[] attributes = (TagAttribute[])mi.GetCustomAttributes(typeof(TagAttribute), true);
        if (attributes.Length == 0)
            // No attributes, continue.
            continue;
        // We assume that at most one attribute is applied to each method.
        TagAttribute attr = attributes[0];
        if (attr.Value == value)
        {
            // The values match, so we call this method.
            methodToCall = mi;
            break;
        }
    }

    if (methodToCall == null)
        throw new InvalidOperationException("No method to call.");

    object result = methodToCall.Invoke(
        // Instance object
        instance,
        // Arguments
        new object[0]);

    // 'result' now contains the return value.
    // It is ignored here.
}

Rufen Sie den CallTaggedMethod von Ihrer Main-Methode:

static void Main(string[] args)
{
    String sequence = "ABCAABBBABACCACC";
    MyClass inst = new MyClass();

    foreach(char c in sequence)
        CallTaggedMethod(inst, c);

    // The rest.

    Console.ReadLine();
}

Hier ist meine Anmerkungen Ansatz. Sie brauchen nicht einmal eine Karte von Tags zu Methoden, wenn Sie Anmerkungen verwenden, nur über die Sequenz durchlaufen und Nachschlagen, das Verfahren für diesen Tag mit Reflexion.

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Tag {
   char value();
}

dann:

public class Base {

   StringBuilder state = new StringBuilder();

   @Tag('A')
   public void method1(){         
      state.append("1");
   }

  @Tag('B')
  public void method2(){              
     state.append("2");
  }

  @Tag('C')
  public void method3(){              
     state.append("3");
  }

  public String getState() {
     return state.toString();
  }
}

dann

public final class TagRunner {

   private TagRunner() {
      super();
   }

   public static void main(String[] args) throws IllegalArgumentException, 
   IllegalAccessException, InvocationTargetException {
      Base b = new Base();
      run(b, "ABCAABBBABACCACC");
      System.out.println(b.getState());
   }

   private static <T> void run(T type, String sequence) throws 
   IllegalArgumentException, IllegalAccessException, InvocationTargetException {
      CharacterIterator it = new StringCharacterIterator(sequence);
      Class<?> taggedClass = type.getClass();

      for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
         getMethodForCharacter(taggedClass, c).invoke(type);    
      }
   }

   private static Method getMethodForCharacter(Class<?> taggedClass, char c) {
      for (Method m : taggedClass.getDeclaredMethods()) {
         if (m.isAnnotationPresent(Tag.class)){
            char value = m.getAnnotation(Tag.class).value();
            if (c == value) {
               return m;
            }
         }      
      }

     //If we get here, there are no methods tagged with this character
     return null;
  }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top