2017-07-19 10 views
-1

C++から来て、現在Java環境で採用されているので、ジェネリックを作成するためにJavaでvoid *とvoid *のマッピングをどのように作成できるのだろうと思いましたAからBへとBからAへのマッピング。私は、JavaにはC++と同じようにポインタと参照がないことに気付いていますが、まだこれを可能にするメソッドを見つけることができません。1クラスから別のクラスに変数をマッピングする一般的なメソッド

私が達成しようとしているものの例:

public class A{ 
    @GenericMapping(1) 
    private Integer temp1; 
} 

public class B{ 
    @GenericMapping(1) 
    private Integer temp2; 
} 

public class Mapper{ 
    private List<Pair<Integer, Integer>> mapping; 
    public void map(Object ObjectOfAnyClassButLetsAssumeA, Object ObjectOfAnyClassButLetsAssumeB){ 
     // Get all parameters with GenericMapping above it, get its value 
     // and match the corresponding value with the value of B 
     // Resulting in A.temp1 = B.temp2; 
    } 
} 

しかし、私はむしろ使用しないようにするために、(マップ[A.temp1] = B.temp2のような)マップを作成したい可能であれば@GenericMappingはそれを見れば、どのような方法でもクラスを変更せずにマッピングを容易にすることができます。

+5

それはあなたが何をしようとして、全く明確ではありません。パラメータ名と同じクラス名があります。あなたのパラメータは 'Object'型として宣言されています。彼らはA型とB型を持っているはずですか?あなたは全く使っていないので、 'mapping'とは何ですか?私はあなたがC++でのやり方をエミュレートしようとするのではなく、あなたがしようとしていることをやるためのもっと簡単な方法がおそらくあるので、まずJavaの基本を学ぶ必要があると思います。 – ajb

+0

マッピングはどのクラスでもかまいませんので、Object型を持つはずです。私はクラスAとクラスBのオブジェクトを呼び出すつもりであることを示すためにAとBという名前を付けました。私のJavaの基本については、私はJavaで1年以上専門的に仕事をしていました。 %...私はそれが私の意図(自閉症を愛する)を誤って伝えている可能性があることに同意しますが。 –

+0

JavaのOOの概念をどのように使って解決しようとしているのかを完全には理解していないJavaプログラマから、多くの疑問があります。あなたは、最終結果が欲しいもの、または開発しようとしているものを(たとえあなたの編集が少し助けても)使う方法についての良い考えを提供していないので、私にとっては難しかったこれが新しいJavaプログラマーの質問ではないことを伝えてください。 – ajb

答えて

1

私はあなたがここでやりたいことを理解していると思いますし、メタデータとJava 8のLambdasを使ってそれを達成できます。

クラスとIDで識別されるすべてのマッピング(@GenericMappingに似ていますが、実際にクラスに注釈を付けずに)を設定し、値を取得および取得するメソッドを含むヘルパークラスを設定します。同じIDのすべてのマッピングが同じ値型を持つか、値を転送するときにClassCastExceptionがスローされることが重要です。

私の例では、すべてのクラスがすべてのクラスに適用されるわけではない3つのクラスを使用しています。

ここでは、コードです:それを実行した後

public class GenericMappingDemo { 

    static class A { 
     private Integer integerA; 
     private String stringA; 
     private Float floatA; 

     public A(final Integer integerA, final String stringA, final Float floatA) { 
      this.integerA = integerA; 
      this.stringA = stringA; 
      this.floatA = floatA; 
     } 

     public Integer getIntegerA() { 
      return integerA; 
     } 

     public void setIntegerA(final Integer integerA) { 
      this.integerA = integerA; 
     } 

     public String getStringA() { 
      return stringA; 
     } 

     public void setStringA(final String stringA) { 
      this.stringA = stringA; 
     } 

     public Float getFloatA() { 
      return floatA; 
     } 

     public void setFloatA(final Float floatA) { 
      this.floatA = floatA; 
     } 

     @Override 
     public String toString() { 
      return "A{integerA=" + integerA + ", stringA='" + stringA + "', floatA=" + floatA + '}'; 
     } 
    } 

    static class B { 
     private Integer integerB; 
     private String stringB; 

     public Integer getIntegerB() { 
      return integerB; 
     } 

     public void setIntegerB(final Integer integerB) { 
      this.integerB = integerB; 
     } 

     public String getStringB() { 
      return stringB; 
     } 

     public void setStringB(final String stringB) { 
      this.stringB = stringB; 
     } 

     @Override 
     public String toString() { 
      return "B{integerB=" + integerB + ", stringB='" + stringB + '\'' + '}'; 
     } 
    } 

    static class C { 
     private Float floatC; 
     private String stringC; 

     public Float getFloatC() { 
      return floatC; 
     } 

     public void setFloatC(final Float floatC) { 
      this.floatC = floatC; 
     } 

     public String getStringC() { 
      return stringC; 
     } 

     public void setStringC(final String stringC) { 
      this.stringC = stringC; 
     } 

     @Override 
     public String toString() { 
      return "C{floatC=" + floatC + ", stringC='" + stringC + "'}"; 
     } 
    } 

    static class GenericMapping<C, T> { 
     final int id; 
     final Class<C> type; 
     final Function<C, T> getter; 
     final BiConsumer<C, T> setter; 

     public GenericMapping(final int id, 
       final Class<C> type, 
       final Function<C, T> getter, 
       final BiConsumer<C, T> setter) { 
      this.id = id; 
      this.type = type; 
      this.getter = getter; 
      this.setter = setter; 
     } 
    } 

    static class Mapper { 
     // All mappings by class and id 
     private final Map<Class<?>, Map<Integer, GenericMapping<?, ?>>> mappings 
       = new HashMap<>(); 

     public void addMapping(GenericMapping<?, ?> mapping) { 
      mappings.computeIfAbsent(mapping.type, 
        c -> new TreeMap<>()).put(mapping.id, mapping); 
     } 

     /** 
     * Map values from one object to another, 
     * using any mapping ids that apply to both classes 
     * @param from The object to transfer values from 
     * @param to The object to transfer values to 
     */ 
     public <From, To> void map(From from, To to) { 
      Map<Integer, GenericMapping<?, ?>> getters 
        = mappings.get(from.getClass()); 
      Map<Integer, GenericMapping<?, ?>> setters 
        = mappings.get(to.getClass()); 
      if (getters == null || setters == null) { 
       // Nothing to do 
       return; 
      } 

      // Create a set with the ids in both getters and 
      // setters, i.e. the mappings that apply 
      Set<Integer> ids = new HashSet<>(getters.keySet()); 
      ids.retainAll(setters.keySet()); 

      // Transfer all mappings 
      for (Integer id : ids) { 
       GenericMapping<From, ?> getter 
         = (GenericMapping<From, ?>) getters.get(id); 
       GenericMapping<To, ?> setter 
         = (GenericMapping<To, ?>) setters.get(id); 
       transfer(from, to, getter, setter); 
      } 
     } 

     private <From, To, V> void transfer(final From from, 
       final To to, final GenericMapping<From, ?> getter, 
       final GenericMapping<To, V> setter) { 
      // This will throw an exception if the mappings are invalid 
      final V value = (V) getter.getter.apply(from); 
      setter.setter.accept(to, value); 
     } 
    } 

    public static void main(String[] args) { 
     final Mapper mapper = new Mapper(); 

     // Mapping definition for class A 
     mapper.addMapping(new GenericMapping<>(1, A.class, 
       A::getIntegerA, A::setIntegerA)); 
     mapper.addMapping(new GenericMapping<>(2, A.class, 
       A::getStringA, A::setStringA)); 
     mapper.addMapping(new GenericMapping<>(3, A.class, 
       A::getFloatA, A::setFloatA)); 

     // Mapping definition for class B 
     mapper.addMapping(new GenericMapping<>(1, B.class, 
       B::getIntegerB, B::setIntegerB)); 
     mapper.addMapping(new GenericMapping<>(2, B.class, 
       B::getStringB, B::setStringB)); 

     // Mapping definition for class C 
     mapper.addMapping(new GenericMapping<>(2, C.class, 
       C::getStringC, C::setStringC)); 
     mapper.addMapping(new GenericMapping<>(3, C.class, 
       C::getFloatC, C::setFloatC)); 

     // Use the mappings 
     A a = new A(7, "foo", 3.7f); 
     B b = new B(); 
     C c = new C(); 

     System.out.printf("A before map: %s%n", a); 
     System.out.printf("B before map: %s%n", b); 
     System.out.printf("C before map: %s%n", c); 

     // This will transfer a.integerA to b.integerB and a.stringA to b.stringB 
     mapper.map(a, b); 
     // This will transfer a.stringA to c.stringC and a.floatA to c.floatC 
     mapper.map(a, c); 

     System.out.println(); 
     System.out.printf("A after map: %s%n", a); 
     System.out.printf("B after map: %s%n", b); 
     System.out.printf("C after map: %s%n", c); 
    } 
} 

そして結果:

A before map: A{integerA=7, stringA='foo', floatA=3.7} 
B before map: B{integerB=null, stringB='null'} 
C before map: C{floatC=null, stringC='null'} 

A after map: A{integerA=7, stringA='foo', floatA=3.7} 
B after map: B{integerB=7, stringB='foo'} 
C after map: C{floatC=3.7, stringC='foo'} 

のJava 7

同じ一般的な解決策は、Java 7のために使用することができますが、それはなりますが、より多くの冗長。 Java 7には機能インタフェースFunction<U, V>BiConsumer<U, V>がないので、これらを自分で定義する必要がありますが、それほど問題はありません。 Java 8で定義する必要がありますので、インターフェース名やメソッド名が意味を成す(例えば、Getter.getSetter.set)と主張することもできます。

ラムダの代わりに匿名のクラスを使用する必要があるマッピングの定義が重要です。lambdasは、匿名クラスのほとんどが構文的に砂糖を使用していますが、どちらか一方のメソッドしかありません。

a.integerAのマッピングは、Java 7で次のようになります。明示的な(ないアノテーションベースのが、あなたはまたもかなり洗練さを持っているのApache Commonsの々BeanUtils、見ている可能性が

mapper.addMapping(new GenericMapping<>(1, A.class, 
     new Function<A, Integer>() { 
      @Override 
      public Integer apply(final A a1) { 
       return a1.getIntegerA(); 
      } 
     }, 
     new BiConsumer<A, Integer>() { 
      @Override 
      public void accept(final A a1, final Integer integerA) { 
       a1.setIntegerA(integerA); 
      } 
     })); 
+1

これは素晴らしいですね! :) 私は完全に私の質問に答えて見て答えとしてマークしたが、私は質問があります:Java 7を使用してこの作品を作るために何が変更する必要がありますか(またはこれはまったく不可能ですか?残念ながら、同社のコードはまだJava 8に移行していません。 –

+0

ありがとうございます。 Java 7のセクションを更新しました。基本的に 'Function'と' BiConsumer'インターフェースを定義し、ラムダを匿名クラスに展開するだけです。 – Raniz

+0

あなたは英雄です:D –

関連する問題