映射超类型并获取子类型

时间:2016-09-03 23:19:17

标签: java java-8

这是一个设计问题。存储Foo对象的映射是不好的做法,其中Foo是一个超类并将查找转换为更具体的对象?即:

Map<Integer, Foo> lookup = new HashMap<>();
lookup.put(0, new Bar()); //Bar extends Foo
lookup.put(1, new Fizz()); // Fizz extends Foo

public Bar getBarById (int barId){
   (Bar)lookup.get(barId);
}

上述方法有多脆弱?在Java8中是否有更好的方法或更好的设计模式可以让我做类似的事情?

2 个答案:

答案 0 :(得分:0)

你有个好主意,但看起来你需要拆分对象。除非您要跟踪他们的密钥,否则您不会知道从地图中取出哪种类型。

因此,如果您输入一个带有键0的新Bar(),您需要将其存储在列表或其他内容中,因此当您只想调用Bar的方法时,您可以查看Bar对象ID的ArrayList。

Map<Integer, Foo> lookup = new HashMap<>();
ArrayList<Integer> listOfBar = new ArrayList<>();
ArrayList<Integer> listOfFizz = new ArrayList<>();

lookup.put(0, new Bar()); //Bar extends Foo
listOfBar.add(0);

lookup.put(1, new Fizz()); // Fizz extends Foo
listOfFizz.add(1);

//in Method to return Bars 
if(listOfBar.size() != 0){
int k = listOfBar.get(0);
Bar b = lookup.get(k);
return b;


}

所以现在可以使用arraylist访问该特定对象的所有id。

答案 1 :(得分:0)

原始代码无法正常工作,因为 getBarbyId()会在您为其提供&#34; Fizz&#34;的ID时失败(在您的示例中为id#1):

// ClassCastException:  System.out.println(this.getBarById(1).getClass().getSimpleName());

您可以使用ArrayList完成相同的操作,但重要的是,如果您想要自己的访问者,您应该将其设为 getFooById ,即使您没有能力改变Foo类。

示例:

import java.util.ArrayList;

public class Main {
    class Foo {
        // Assume defined elsewhere and we can't change it
    }

    class Bar extends Foo {}
    class Fizz extends Foo {}

    public Foo getFooById(int id) {
        return fooList.get(id);
    }

    ArrayList<Foo> fooList = new ArrayList<>();

    Main() {
        fooList.add(0, new Bar());      // keys optional here, unless you are 
        fooList.add(1, new Fizz());     // looking for specific entries later

        for (int i=0; i < fooList.size(); i++) {
            System.out.println("foo:  " + i + " " + getFooById(i).getClass().getSimpleName());
        }
    }


    public static void main(String[] args) {
        Main m = new Main();
    }
}

<强>输出:

foo:  0 Bar
foo:  1 Fizz