代码之家  ›  专栏  ›  技术社区  ›  TofuBeer

泛型调用构造函数

  •  0
  • TofuBeer  · 技术社区  · 16 年前

    我在做一些我通常不会做的事情,这有点奇怪,但我想让它工作。本质上,我有一个工厂,它必须通过使用不同类型的数据(在下面的代码中,A和B采用不同的类型)调用构造函数来创建对象。我似乎已经陷入了泛型的困境(我确实需要代码尽可能的在编译时保持类型安全)。我并不反对以不同的方式编写代码(如果可能的话,我想保留工厂的想法,并且我不想添加强制转换——所以“data”参数不能是“object”)。

    有没有想过如何用泛型或其他满足我需求的方法来修复代码?

    (从技术上讲,这是家庭作业,但我是正在尝试新事物的老师……所以这不是真正的家庭作业:—)

    public class Main2
    {
        public static void main(String[] args) 
        {
            X<?> x;
    
            x = XFactory.makeX(0, "Hello");
            x.foo();
    
            x = XFactory.makeX(1, Integer.valueOf(42));
            x.foo();
        }
    
    }
    
    class XFactory
    {
        public static <T> X<T> makeX(final int i,
                                     final T   data)
        {
            final X<T> x;
    
            if(i == 0)
            {
                // compiler error: cannot find symbol constructor A(T)
                x = new A(data);
            }
            else
            {
                // compiler error: cannot find symbol constructor B(T)
                x = new B(data);
            }
    
            return (x);
        }
    }
    
    interface X<T>
    {
        void foo();
    }
    
    class A
        implements X<String>
    {
        A(final String s)
        {
        }
    
        public void foo()
        {
            System.out.println("A.foo");
        }
    }
    
    class B
        implements X<Integer>
    {
        B(final Integer i)
        {
        }
    
        public void foo()
        {
            System.out.println("B.foo");
        }
    }
    
    4 回复  |  直到 14 年前
        1
  •  1
  •   wds    16 年前

    我看不出有什么办法让它发挥作用。我真的认为它也不应该起作用。打电话给你的时候 makeX() 函数调用代码需要知道哪个整型参数对应于要传入的数据类型。首先,您的抽象是非常漏洞百出的,您真正实现的是一种基本形式的多态性,您也可以将方法重载用于,即:

    X makeX(String data) {
      return new A(data);
    }
    
    X makeX(Integer data) {
      return new B(data);
    }
    

    当然,这是个玩具问题。使其工作的一种方法是使客户机了解实现类并添加 Class<T> 通过反射实例化的参数。但我认为这有点破坏了目标。

        2
  •  1
  •   Reverend Gonzo    16 年前

    我不认为你想做的事没有演员阵容是不可能的。

    有了演员阵容,你有两个选择

    if(i == 0)
            {
                x = new A((Integer)data);
            }
            else
            {
                x = new B((String)data);
         }
    }
    

    class A
        implements X<String>
    {
        A(final Object s)
        {
        }
    }
    
    ...
    
    class B
        implements X<Integer>
    {
        B(final Object i)
        {
        }
    }
    
        3
  •  1
  •   Tom Hawtin - tackline    16 年前

    在保持静态类型的安全性和惰性结构的同时,可能最接近的是:

    public static void main(String[] args) {
        X<?> x;
    
        x = aFactory("Hello").makeX();
        x.foo();
    
        x = bFactory(42).makeX();
        x.foo();
    }
    
    private static XFactory aFactory(final String value) {
        return new XFactory() { public X<?> makeX() {
            return new A(value);
        }};
    }
    
    public static XFactory bFactory(final Integer value) {
        return new XFactory() { public X<?> makeX() {
            return new B(value);
        }};
    }
    
    interface XFactory() {
         X<?> makeX();
    }
    

    因此,我们创建一个抽象工厂的实例,用适当的参数创建适当的实例。作为一家工厂,该产品只能按需生产。

    很明显,必须付出点什么。你期望什么 XFactory.makeX(1, "Hello") 做什么?

        4
  •  0
  •   PaulMurrayCbr    14 年前

    没有铸造是不可能的。正如我在其他地方说过的,仿制药并不能消除铸造的需要,但它们意味着你可以在一个地方完成所有铸造。

    在您描述的设置中,工厂方法正是所有引擎盖下工作发生的地方。你的代码告诉编译器“我知道” 不知道这些类型是什么,但是 做,所以放松。

    您的工厂方法完全可以清楚地知道,如果i==1,那么数据必须是integer类型,并且要用casting检查/执行这个类型。