문제

기본 클래스에서 여러 메소드를 태그하는 방법을 찾아서 클라이언트 클래스가 태그로 호출 할 수 있도록 노력하고 있습니다. 예제 코드는 다음과 같습니다.

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 () 메소드의 클라이언트 클래스는 임의의 명령 시퀀스를 통해 각 기본 메소드를 호출합니다.

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

    }

이제 클라이언트 객체에서 스위치 문을 모두 제거하고 싶습니다. 나는 다형성으로 스위치를 대체하는 기술을 알고 있지만 피하다 새로운 클래스 세트 만들기. 나는 그 방법을 적절한 데이터 구조에 간단히 저장하고 어떻게 든 시퀀스에서 일치하는 문자로 태그를 지정하기를 바랐다.

지도는 값/키 쌍이있는 객체를 쉽게 저장할 수있는 작업을 수행 할 수 있습니다 (내가했던 것처럼 여기) 또는 명령 패턴이지만 해당 메소드를 객체로 바꾸고 싶지 않기 때문에 방법을 저장하고 클라이언트가 선택적으로 전화 할 수있는 다른 방법이 있습니까?

모든 조언에 감사드립니다

도움이 되었습니까?

해결책

이 같은?

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

}

그리고

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

다른 팁

나는 사용할 것이다 주석 해당 메소드에서 "태그 된 메소드"로 표시 할 수있게하고 해당 메소드에 사용할 태그 문자열을 제공합니다.

그 시점부터 구현이 더 간단 해집니다. 반사를 사용하여 클래스의 방법을 반복하고 주석을 검사 할 수 있습니다. 아마도이 작업을 정적으로 시작하고 태그 문자열에서 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);
      }
   }
}

다음과 같이 액세스 할 수 있습니다.

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

}

이 코드는 컴파일되거나 테스트되지 않았습니다. 그런데 ... :-)

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 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;
  }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top