وضع علامات على الطرق ودعوتهم من كائن العميل حسب العلامة

StackOverflow https://stackoverflow.com/questions/1400305

سؤال

ولقد سعيت لمعرفة طريقة لوضع علامة عدة طرق من الفئة الأساسية بلدي، لذلك أن فئة العميل يمكن استدعاء لهم من قبل العلامة. رمز المثال هو:

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

وسوف فئة العميل من الطريقة الرئيسية () دعوة لكل طريقة من قاعدة من خلال سلسلة تعليمات عشوائي:

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

    }

والآن أود أن تخلص من بيان التبديل تماما من وجوه العملاء. أنا على علم تقنية ليحل محل التبديل من تعدد الأشكال، ولكن أود أن <م> تجنب خلق مجموعة من فئات جديدة. وكنت آمل أن مجرد تخزين تلك الأساليب في بنية البيانات المناسبة وبطريقة أو بأخرى علامة لهم طابع المطابقة من التسلسل.

وخريطة يمكن بسهولة تخزين الكائنات مع قيمة زوجا / الرئيسية التي يمكن القيام بهذه المهمة، (كما فعلت <لأ href = "https://stackoverflow.com/questions/1386673/trouble-making-polymorphism-defeat-those -switch-حالة على تصريحات "> هنا )، أو نمط القيادة، ولكن منذ أن كنت لا تريد استبدال تلك الأساليب مع الأشياء، وهناك طريقة مختلفة ربما، لتخزين وسائل ويكون العميل الاتصال بشكل انتقائي لهم؟

وهو موضع تقدير أي نصيحة

هل كانت مفيدة؟

المحلول

وشيء من هذا القبيل؟

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 #. لجافا، استخدم شروحه. اشتقاق فئة من الطبقة سمة، أقول، 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