如何实现可指定成员变量与对应值的setPartProperties方法?
Got it, let's work through this problem step by step. The main goals here are replacing that unsuitable Parameter type with a proper key-value pair structure, and using reflection to dynamically set your Part class's member variables without needing a HashMap. Here's how to do it:
Step 1: Create a Reusable Pair Class
First, we need a simple way to pass field-name and value pairs. We'll make a generic Pair class (either as a static inner class in Part or a top-level class) to hold these pairs. A static factory method will make the calling syntax clean, matching your desired (x, 100) style.
// Add this inside the Part class (or as a separate top-level class) public static class Pair<K, V> { private final K key; private final V value; // Private constructor to enforce using the factory method private Pair(K key, V value) { this.key = key; this.value = value; } // Clean factory method for creating pairs public static <K, V> Pair<K, V> of(K key, V value) { return new Pair<>(key, value); } // Getters to access the key/value public K getKey() { return key; } public V getValue() { return value; } }
Step 2: Refactor the setPartProperties Method
Replace the Parameter... parameter with our Pair<String, Object>... (since field names are strings, and values can be any type matching your member variables). We'll use reflection to iterate over each pair and set the corresponding field:
public void setPartProperties(Pair<String, Object>... properties) { for (Pair<String, Object> property : properties) { String fieldName = property.getKey(); Object value = property.getValue(); try { // Get the field from the current class (supports subclasses too) Field field = this.getClass().getDeclaredField(fieldName); // Allow access to package-private fields like your x/y/width/etc. field.setAccessible(true); // Set the field value for this instance field.set(this, value); } catch (NoSuchFieldException e) { throw new IllegalArgumentException("Field '" + fieldName + "' doesn't exist in " + this.getClass().getSimpleName(), e); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Can't access field '" + fieldName + "'", e); } catch (ClassCastException e) { throw new IllegalArgumentException("Value type doesn't match field '" + fieldName + "'", e); } } }
Step 3: Update the Wheel Subclass Constructor
Now we can call the method with the clean Pair.of() syntax, which aligns with your desired input style:
public Wheel(double x, double y, double width, double height, double angle) { super(x, y, width, height, angle); // Pass key-value pairs using our Pair factory method setPartProperties( Pair.of("x", 100.0), Pair.of("y", 100.0), Pair.of("width", 50.0), Pair.of("height", 40.0), Pair.of("angle", 0.0) ); }
Full Modified Code
Updated Part Class
import com.sun.javafx.geom.Shape; import javafx.scene.Group; import java.lang.reflect.Field; public abstract class Part { double x; double y; double width; double height; double angle; // Generic Pair class for key-value property pairs public static class Pair<K, V> { private final K key; private final V value; private Pair(K key, V value) { this.key = key; this.value = value; } public static <K, V> Pair<K, V> of(K key, V value) { return new Pair<>(key, value); } public K getKey() { return key; } public V getValue() { return value; } } public Part(double x, double y, double width, double height, double angle) { this.x = x; this.y = y; this.width = width; this.height = height; this.angle = angle; Group group = new Group(); group.getChildren().addAll(); } abstract void createPart(Shape shape); abstract void addPart(Group group); public void setPartProperties(Pair<String, Object>... properties) { for (Pair<String, Object> property : properties) { String fieldName = property.getKey(); Object value = property.getValue(); try { Field field = this.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(this, value); } catch (NoSuchFieldException e) { throw new IllegalArgumentException("Field '" + fieldName + "' not found in " + getClass().getSimpleName(), e); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Cannot access field '" + fieldName + "'", e); } catch (ClassCastException e) { throw new IllegalArgumentException("Value type mismatch for field '" + fieldName + "'", e); } } } }
Updated Wheel Class
import com.sun.javafx.geom.Shape; import javafx.scene.Group; public class Wheel extends Part { public Wheel(double x, double y, double width, double height, double angle) { super(x, y, width, height, angle); setPartProperties( Pair.of("x", 100.0), Pair.of("y", 100.0), Pair.of("width", 50.0), Pair.of("height", 40.0), Pair.of("angle", 0.0) ); } @Override public void createPart(Shape shape) { // Implement your JavaFX circle creation logic here } @Override public void addPart(Group group) { // Implement adding your shape to the group here } }
Key Notes
- Reflection Usage: We use reflection to dynamically access fields by name, which lets us modify any member variable without writing separate setters for each.
- Error Handling: Wrapping reflection exceptions in
IllegalArgumentExceptiongives clear, actionable error messages if a field doesn't exist, can't be accessed, or the value type is wrong. - Clean Syntax: The
Pair.of()method keeps the method call concise, just like your original desired(x, 100)format.
内容的提问来源于stack exchange,提问作者KNOB Personal

