【问题标题】:How do I define or refer properties of model classes that is going to be used in the view如何定义或引用将在视图中使用的模型类的属性
【发布时间】:2012-11-08 06:18:36
【问题描述】:

我想让开发人员必须定义要在视图中显示的“模型”类的属性。

我曾想过使用枚举作为解决方案,但我认为不可能在超类(接口)中定义枚举。

如果我的描述不清楚,我很抱歉。有点难以解释。我会尝试用一个具体的案例来解释。

Animal.java

public interface Animal {
    public void eat();
}

Bird.java

public class Bird implements Animal
{
    private String name;
    private int age;
    private Beak beak;
    private Wings wings;

    public Bird(String name, int age, Beak beak, Wings wings)
    {
        this.name = name;
        this.age = age;
        this.beak = beak;
        this.wings = organ;
    }

    //getter setter..

    @Override
    public void eat() {
        //eating
    }
}

Snake.java

public class Snake implements Animal
{
    private String name;
    private int age;
    private Fang fangs;

    public Snake(String name, int age, Fang fangs)
    {
        this.name = name;
        this.age = age;
        this.fangs = fangs;
    }

    //getter setter..

    @Override
    public void eat() {
        //eating
    }
}

动物园.java

public class Zoo 
{
    private ArrayList<Bird> birds = new ArrayList<Bird>();
    private ArrayList<Snake> snakes = new ArrayList<Snake>();
    private ArrayList<Object?> birdsShownFeatures = new ArrayList<Object?>();
    private ArrayList<Object?> snakesShownFeatures = new ArrayList<Object?>();

    public Zoo()
    {
        birds.add(new Bird("Vulture", 2, new CrookedBeak(), new WideWing()));
        birds.add(new Bird("Whatever", 3, new WhateverBeak(), new WhateverWing()));
        birds.add(new Bird("Wut", 4, new WutBeak(), new WutWing()));

        snakes.add(new Snake("Cobra", 5, new TwinFang()));
        snakes.add(new Snake("Whatever", 5, new WhateverFang()));
        snakes.add(new Snake("Wut", 5, new WutFang()));

        birdsShownFeatures.add(new Object?("name"));
        birdsShownFeatures.add(new Object?("beak"));
        birdsShownFeatures.add(new Object?("wings"));

        snakesShownFeatures.add(new Object?("name"));
        snakesShownFeatures.add(new Object?("fangs"));
    }

    public void showOff()
    {
        for(Bird bird:birds)
        {
            for(Object? object:birdsShownFeatures)
            {
                System.out.println("Bird: "+bird.unknownFunction(object));
            }
        }

        for(Snake snake:snakes)
        {
            for(Object? object:snakesShownFeatures)
            {
                System.out.println("Snake: "+snake.unknownFunction(object));
            }
        }
    }
}

我必须概括Animal(Object?)的子类的属性。而且我必须能够定义一个函数来检索该属性(unknownFunction)。

换句话说,我希望能够轻松定义动物子类的某些属性并能够进行相应的处理。

完美(不真实?)示例:

public class Zoo {
    private ArrayList<Bird> birds = new ArrayList<Bird>();
    private ArrayList<Snake> snakes = new ArrayList<Snake>();
    private ArrayList<Object> birdsShownFeatures = new ArrayList<Object>();
    private ArrayList<Object> snakesShownFeatures = new ArrayList<Object>();

    public Zoo()
    {
        birds.add(new Bird("Vulture", 2, new CrookedBeak(), new WideWing()));
        birds.add(new Bird("Whatever", 3, new WhateverBeak(), new WhateverWing()));
        birds.add(new Bird("Wut", 4, new WutBeak(), new WutWing()));

        snakes.add(new Snake("Cobra", 5, new TwinFang()));
        snakes.add(new Snake("Whatever", 5, new WhateverFang()));
        snakes.add(new Snake("Wut", 5, new WutFang()));

        birdsShownFeatures.add(Bird.NAME);
        birdsShownFeatures.add(Bird.BEAK);
        birdsShownFeatures.add(Bird.WINGS);

        snakesShownFeatures.add(Snake.NAME);
        snakesShownFeatures.add(Snake.FANGS);
    }

    public void showOff()
    {
        for(Bird bird:birds)
        {
            for(Object object:birdsShownFeatures)
            {
                System.out.println("Bird: "+bird.get(object));
            }
        }

        for(Snake snake:snakes)
        {
            for(Object object:snakesShownFeatures)
            {
                System.out.println("Snake: "+snake.get(object));
            }
        }
    }
}

枚举无法工作,因为我无法强制开发人员在每次创建实现 Animal 的类时创建实现接口的特定枚举。

蛇和鸟的属性都必须能够概括。但还是定义了。让每个属性都实现一个特定的接口不是一种选择,因为让所有需要的类(包括原生类)都实现一个接口会很痛苦。

对不起,如果它太混乱了。我不知道如何正确解释这种情况。

【问题讨论】:

  • 看看 Java 的反射 API 和注解。
  • 我读过一些关于它们的文章。我发现我可以通过执行 Field f = class.getField("fieldName"); 来获取字段引用。您是否知道开发人员无需做所有麻烦即可获得字段的更简单方法(getClass,getField(“FieldName”))。此外,“FieldName”字符串不受限制。所以很容易出现人为错误。返回字段的 Class.FieldName 将是最好的。如果它是可能的。我应该枚举字段还是什么?

标签: java oop model-view-controller


【解决方案1】:

您可以使用反射和泛型。这是您问题的答案,但我认为这是一个糟糕的选择。

使用您的表格示例(请参阅 cmets)我会使用类似于通用 Table&lt;T&gt; 的方法和返回一行的 getRow() 方法(对于 Bird"Vulture", 2, "CrookedBeak", "WideWing"),如果最终开发人员想要一种不同的行,他可以将您的getRow 覆盖为其他内容。 另一种选择是在表构造函数中接受Function&lt;T, Row&gt;(参见google guava functions


快速而肮脏的示例泛型和反射代码示例:

抽象动物

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

public abstract class AbstractAnimal<T extends Enum<T>> {
    private List<T> selectedFields = new ArrayList<T>();

    public AbstractAnimal(Class<T> clazz)
    {
        if (clazz != null) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                if (Modifier.isStatic(field.getModifiers()) && 
                    Modifier.isPublic(field.getModifiers())) {
                    this.selectedFields.add(Enum.valueOf(clazz, field.getName()));
                }
            }
        }
    }

    public abstract void eat();

    public List<T> getSelectedFields()
    {
        return this.selectedFields;
    }

    public Object get(T name)
    {
        if (name == null) {
            return null; 
        }

        try {
            final Class<?> clazz = this.getClass();
            final Field declaredField = clazz.getDeclaredField(name.name().toLowerCase());
            if (declaredField != null) {
                declaredField.setAccessible(true);
                return declaredField.get(this);
            }
        } catch (IllegalAccessException ex) {
            // ignore
        } catch (NoSuchFieldException e) {
            // ignore
        } catch (SecurityException e) {
            // ignore
        }
        return null;
    }
}

public class Bird extends AbstractAnimal<Bird.Fields> {

    public static enum Fields {
        NAME, AGE, BEAK, WINGS
    }

    private String name;

    private int age;

    private String beak;

    private String wings;

    public Bird(String name, int age, String beak, String wings)
    {
        super(Fields.class);
        this.name = name;
        this.age = age;
        this.beak = beak;
        this.wings = wings;
    }

    // getter setter..

    @Override
    public void eat()
    {
        // eating
    }
}

动物园

package com.foo;

import java.util.ArrayList;

public class Zoo {
    private ArrayList<Bird> birds = new ArrayList<Bird>();

    public Zoo()
    {
        birds.add(this.buildBird("Vulture", 2, "CrookedBeak", "WideWing"));
        birds.add(this.buildBird("Whatever", 3, "WhateverBeak", "WhateverWing"));
        birds.add(this.buildBird("Wut", 4, "WutBeak", "WutWing"));
    }

    public void showOff()
    {
        for(Bird bird:birds)
        {
            for (final Bird.Fields selectedField : bird.getSelectedFields()) {
                System.out.println("bird: " + bird.get(selectedField));
            }
        }
    }

    private Bird buildBird(String name, int age, String beak, String wings) 
    {
        Bird result = new Bird(name, age, beak, wings);
        result.getSelectedFields().remove(Bird.Fields.AGE);
        return result;
    }

    public static void main(final String[] args) {
        Zoo z = new Zoo();
        z.showOff();
    }
}

输出

bird: Vulture
bird: CrookedBeak
bird: WideWing
bird: Whatever
bird: WhateverBeak
bird: WhateverWing
bird: Wut
bird: WutBeak
bird: WutWing

【讨论】:

  • 嗯,如果我想在 Zoo 类中指定 shownAttribute 以使其动态化怎么办?我希望能够动态定义在 showOff() 中显示哪些字段。
  • 哼,我想我误解了你的需要。你能澄清一下你所说的动态是什么意思吗?我的意思是大局?
  • 你看,在我的动物园课上。我通过将它们添加到 ShownFeatures Arraylist 中选择了显示属性。当您通过向每个子类中的属性添加注释来选择它们时。这意味着在您的解决方案中,假设开发人员只能操作 Zoo,则开发人员无法为自己选择属性。如果我能将“某物”放入 ShownFeatures 中作为属性的引用……但是“某物”必须受到约束,以便开发人员只能放置实际的字段引用以减少人为错误。
  • 我还是看不到这个的用法,我的意思是你给我一个带有Bird和co的jar,我想打印Snake的一些属性,我会使用getter和让我们走吧,您选择公开或不公开某些属性的方式是提供或不提供 getter(在这种情况下),不是吗?
  • 好的,假设我有一个包含 Zoo 类的库,该类接受选定的字段和一组鸟类。该系统非常复杂,开发人员不需要关心这一点。他们需要关心的是选择使用 Bird 类的哪些字段。所以这个函数可能是这样的 doComplexThing(listOfChosenFields, arrayOfEntities)。我能想到的最简单的例子可能是 Table。表格可以选择要显示给表格的实体的哪些字段。假设我希望开发人员能够选择它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多