求带泛型List字段的DialogCar类的Builder模式实现方案
Got it, let's work through this together. You need a Builder pattern for your generic DialogCar<T> class that implements Parcelable, with proper handling for the List<T> field. Here's a complete, robust implementation that covers both the Parcelable requirements and the generic Builder logic.
Complete Implementation
import android.os.Parcel; import android.os.Parcelable; import java.util.ArrayList; import java.util.List; public class DialogCar<T extends Parcelable> implements Parcelable { private final String type; private final List<T> selectedValues; // Private constructor, only accessible via Builder private DialogCar(Builder<T> builder) { this.type = builder.type; // Make a copy of the list to prevent external modifications to internal state this.selectedValues = new ArrayList<>(builder.selectedValues); } // Parcelable deserialization constructor protected DialogCar(Parcel in) { type = in.readString(); // Read generic list using the class loader to handle type T selectedValues = in.readArrayList(getClass().getClassLoader()); } public static final Creator<DialogCar> CREATOR = new Creator<DialogCar>() { @Override public DialogCar createFromParcel(Parcel in) { return new DialogCar(in); } @Override public DialogCar[] newArray(int size) { return new DialogCar[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(type); dest.writeList(selectedValues); } // Getters with state protection public String getType() { return type; } public List<T> getSelectedValues() { // Return a copy to prevent external code from modifying the internal list return new ArrayList<>(selectedValues); } // Generic Builder inner class public static class Builder<T extends Parcelable> { private String type; private List<T> selectedValues = new ArrayList<>(); public Builder<T> type(String type) { this.type = type; return this; } // Set the entire list of selected values public Builder<T> selectedValues(List<T> selectedValues) { if (selectedValues != null) { this.selectedValues.clear(); this.selectedValues.addAll(selectedValues); } return this; } // Convenience method to add a single selected value public Builder<T> addSelectedValue(T value) { if (value != null) { this.selectedValues.add(value); } return this; } public DialogCar<T> build() { // Optional validation to ensure required fields are set if (type == null || type.trim().isEmpty()) { throw new IllegalArgumentException("Type cannot be null or empty"); } return new DialogCar<>(this); } } }
Key Details Explained
- Generic Constraint:
T extends Parcelableis required because we're serializing/deserializingList<T>via Parcel. If yourTdoesn't need to be Parcelable, you can remove this constraint—but note that the Parcelable implementation will break unless you also remove the Parcelable logic entirely. - State Immutability: We copy the list in both the
DialogCarconstructor and thegetSelectedValues()method. This prevents external code from modifying the internal state of theDialogCarinstance after it's built. - Flexible List Handling: The Builder includes both
selectedValues()(to set the entire list) andaddSelectedValue()(to add individual items) for convenience. - Validation: The
build()method includes a basic check for a non-emptytypefield—you can extend this to add more validation rules as needed (e.g., ensuringselectedValuesisn't empty if required).
Usage Example
First, let's define a sample Parcelable class to use as our generic type T:
import android.os.Parcel; import android.os.Parcelable; public class CarOption implements Parcelable { private String label; public CarOption(String label) { this.label = label; } protected CarOption(Parcel in) { label = in.readString(); } public static final Creator<CarOption> CREATOR = new Creator<CarOption>() { @Override public CarOption createFromParcel(Parcel in) { return new CarOption(in); } @Override public CarOption[] newArray(int size) { return new CarOption[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(label); } }
Now you can use the Builder to create DialogCar instances in two ways:
// 1. Build with a pre-existing list List<CarOption> options = new ArrayList<>(); options.add(new CarOption("Electric")); options.add(new CarOption("Hybrid")); DialogCar<CarOption> dialogCar1 = new DialogCar.Builder<CarOption>() .type("car_power_type") .selectedValues(options) .build(); // 2. Build by adding individual items one by one DialogCar<CarOption> dialogCar2 = new DialogCar.Builder<CarOption>() .type("car_body_style") .addSelectedValue(new CarOption("SUV")) .addSelectedValue(new CarOption("Sedan")) .addSelectedValue(new CarOption("Truck")) .build();
内容的提问来源于stack exchange,提问作者ghufranne
相关产品推荐
相关产品推荐

