简体   繁体   中英

How do I define or refer properties of model classes that is going to be used in the view

I want to make the situation where the developers have to define the properties of "model" classes to be shown in the views.

I've thought of using enumeration as the solution, but I don't think it is possible to define enumeration in a superclass (interface).

I'm sorry if my description is unclear. It's kinda hard to explain. I'll try explaining with a specific case.

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

Zoo.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));
            }
        }
    }
}

I have to generalize the attributes of the subclasses of Animal (Object?). And I have to be able to define a function to retrieve that attribute (unknownFunction).

In other words, I want be able to make certain properties of animal's subclasses to be defined easily and are able to be processed accordingly.

Perfect (unreal?) Example:

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

enums can't work because I can't FORCE the developers to make specific enumeration that implements an interface everytime they make a class that implements Animal.

Both snakes and birds attributes have to be able to be generalized . But still defined. Making every attribute to implement a specific interface isn't a choice because it will be a pain in the a** to make all needed classes (including natives) implement an interface.

Sorry if it's too confusing. I don't know how to explain this case properly.

You could use reflection and generics. This answer to your problem but I thinks it's a bad choice.

Using your table example (see comments) I would use something like a generic Table<T> with a getRow() method returning a row (for Bird : "Vulture", 2, "CrookedBeak", "WideWing" ) and if the final developper wants a different kind of row, he can overrides your getRow to something else. Another option would be to accept a Function<T, Row> in the table constructor (see google guava functions )


Quick & dirty sample generic and reflection code sample:

AbstractAnimal

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

Bird

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

Zoo

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

Output

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM