Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 标记方法并通过标记从客户端对象调用它们_Java_Design Patterns_Oop_Methods_Switch Statement - Fatal编程技术网

Java 标记方法并通过标记从客户端对象调用它们

Java 标记方法并通过标记从客户端对象调用它们,java,design-patterns,oop,methods,switch-statement,Java,Design Patterns,Oop,Methods,Switch Statement,我一直在试图找到一种方法来标记基类中的几个方法,以便客户机类可以通过标记来调用它们。示例代码为: public class Base { public void method1(){ ..change state of base class } public void method2(){ ..change state of base class } public void method3

我一直在试图找到一种方法来标记基类中的几个方法,以便客户机类可以通过标记来调用它们。示例代码为:

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
    }
}
main()方法中的客户端类将通过随机指令序列调用Base的每个方法:

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());

    }
publicstaticvoidmain(字符串[]args){
字符串序列=“abcaabbabaccacc”
基基=新基();
对于(int i=0;i
现在我希望从客户机对象中完全去掉switch语句。我知道用多态性代替switch的技术,但希望避免创建一组新类。我希望简单地将这些方法存储在适当的数据结构中,并以某种方式使用序列中的匹配字符标记它们

映射可以很容易地存储具有值/键对的对象,这些值/键对可以完成任务(正如我所做的),或者命令模式,但是由于我不想用对象替换这些方法,是否有其他方法来存储方法并让客户机有选择地调用它们

非常感谢我在讨论中的方法上使用的任何建议,允许将其标记为“标记的方法”,并提供用于该方法的标记字符串

从那时起,实现变得更简单;您可以使用反射来迭代类的方法并检查它们的注释;可能在启动时静态地执行此操作,并填充从标记字符串到java.lang.reflect.Method的映射

然后在处理命令字符串时,调用与每个标记对应的方法

编辑:一些示例代码:

import java.lang.annotation.*; 

@Retention(RetentionPolicy.RUNTIME)
@interface TaggedMethod {
    String tag();
}
然后在基类中:

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
   }
}
…在客户机中:

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);
      }
   }
}
private static final Map taggedMethods=new HashMap();
//设置标记映射
静止的
{
对于(方法m:Base.class.getDeclaredMethods())
{
TaggedMethod annotation=m.getAnnotation(TaggedMethod.class)
if(注释!=null)
{
taggedMethods.put(annotation.tag(),m);
}
}
}
以便您可以通过以下方式访问:

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());

}
publicstaticvoidmain(字符串[]args)引发异常
{
字符串序列=“abcaabbabaccacc”
基基=新基();
对于(int i=0;i
顺便说一下,这段代码尚未编译或测试…:-)

像这样的

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() {}

}
公共类基{
私有最终映射方法=new HashMap();
public Base()引发SecurityException,NoSuchMethodException{
方法.put('A',getClass().getMethod(“method1”);
方法.put('B',getClass().getMethod(“method2”);
方法.put('C',getClass().getMethod(“method3”);
}
公共方法getMethod(charc){
返回方法。get(c);
}
public void method1(){}
public void method2(){}
public void method3(){}
}
然后

    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);
        }
    }
publicstaticvoidmain(字符串[]args)引发异常{
字符串序列=“abcaabbabaccacc”;
基基=新基();
对于(int i=0;i
您可以在C#中为此使用属性。对于Java,使用注释。从属性类(比如TagAttribute)派生一个类,并将该属性应用于方法

[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; }
    }
}
将该属性应用于以下方法:

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"); }
}
使用反射调用方法:

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.
}
从主方法调用CallTaggedMethod:

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

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

    // The rest.

    Console.ReadLine();
}

这是我的注释方法。如果使用注释,甚至不需要标记到方法的映射,只需迭代序列并使用反射查找该标记的方法

import java.lang.annotation.*;

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

然后

public final class TagRunner{
私人TagRunner(){
超级();
}
公共静态void main(字符串[]args)抛出IllegalArgumentException,
IllegaAccessException,InvocationTargetException{
基b=新基();
运行(b,“abcaabbaccacc”);
System.out.println(b.getState());
}
私有静态无效运行(T类型,字符串序列)抛出
IllegalArgumentException、IllegalAccessException、InvocationTargetException{
Characterizer it=新字符串Characterizer(序列);
类taggedClass=type.getClass();
for(char c=it.first();c!=CharacterIterator.DONE;c=it.next()){
getMethodForCharacter(taggedClass,c).invoke(类型);
}
}
私有静态方法getMethodForCharacter(类taggedClass,char c){
对于(方法m:taggedClass.getDeclaredMethods()){
如果(m.isAnnotationPresent(标记类)){
char value=m.getAnnotation(Tag.class).value();
if(c==值){
返回m;
}
}      
}
//如果我们到了这里,就没有用这个字符标记的方法了
返回null;
}
}

@skaffman:感谢您的详细说明,对于最简单的解决方案,它看起来非常整洁,而且非常严格+1,尽管我仍然认为放弃反射开销并使用命令模式会更好。可能吧,但我对此表示怀疑。现在反射开销非常小,对于几乎所有的java框架来说都足够快。@dtsazz
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();
  }
}
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;
  }
}