多くのコンストラクタやオプションパラメーターが必要なクラスを作成するときにBuilderというデザインパターンがあります。
私はEffective Javaで紹介されているパターンを利用しています。
非常に美しくクラスが作れる素晴らしいパターンですね。
さて、で、Builderパターンで作成したクラスのサブクラスをどうするの?
という疑問がありまして、下記に答えがありましたが、日本語情報があまりなかったので、書いておきます。
http://stackoverflow.com/questions/17164375/subclassing-a-java-builder-class
Offer(オファー)というクラスがあり、そのサブクラスでDone(成約)というものがあります。
まずは、Offerで利用するビルダーでジェネリクスを利用するように変更します。
public class Offer { private final String offer_id; private final int offer_price; protected final ArrayList<Delivery> delivery_list; private final int bid_number; private final int more_number; private final MatchRate match_rate; private final boolean is_bid; private final boolean is_more; private final boolean is_matched; private final String winner_id; private final String status; private final boolean is_approved; //成約しているかどうか private final String bidder_id; protected final int max_weight; protected final int number_of_delivery; protected final int number_of_sender; protected final int take_over; protected final boolean is_pack; protected final int company_id; protected final String company_name; protected final double company_review; protected final int pack_id; protected final Pack pack; public static class Builder<T extends Builder> { //必須パラメーター private final String offer_id; private final int offer_price; private final ArrayList<Delivery> delivery_list; //オプションパラメーター 初期値を設定 private int bid_number = 0; private int more_number = 0; private MatchRate match_rate = MatchRate.NOT_GOOD; private boolean is_bid = false; private boolean is_more = false; private boolean is_matched = false; private String winner_id; private String status; private boolean is_approved; private String done_id; private String bidder_id = null; private int max_weight; private int number_of_delivery = 0; private int number_of_sender = 0; private int take_over = 0; private boolean is_pack = false; private int company_id; private String company_name; private double company_review; private int pack_id; private Pack pack; /** * @param offer_id * @param offer_price * @param delivery_list */ public Builder(String offer_id, int offer_price, ArrayList<Delivery> delivery_list) { this.offer_id = offer_id; this.offer_price = offer_price; this.delivery_list = delivery_list; } public T bid_number(int val) { bid_number = val; return (T)this; } public T more_number(int val) { more_number = val; return (T)this; } public T match_rate(MatchRate val) { match_rate = val; return (T)this; } public T is_bid(boolean val) { is_bid = val; return (T)this; } public T is_more(boolean val) { is_more = val; return (T)this; } public T is_matched(boolean val) { is_matched = val; return (T)this; } public T status(String val) { status = val; return (T)this; } public T winner_id(String val) { winner_id = val; if (winner_id != null) { is_matched = true; } return (T)this; } public T is_approved(boolean val) { is_approved = val; return (T)this; } public T done_id(String val) { done_id = val; return (T)this; } public T bidder_id(String val) { bidder_id = val; return (T)this; } public T max_weight(int val) { max_weight = val; return (T)this; } public T number_of_delivery(int val) { number_of_delivery = val; return (T)this; } public T number_of_sender(int val) { number_of_sender = val; return (T)this; } public T take_over(int val) { take_over = val; return (T)this; } public T is_pack(boolean val) { is_pack = val; return (T)this; } public T company_id(int val) { company_id = val; return (T)this; } public T company_name(String val) { company_name = val; return (T)this; } public T company_review(double val){ company_review = val; return (T)this; } public T pack_id(int val) { pack_id = val; return (T)this; } public T pack(Pack val) { pack = val; return (T)this; } public Offer build() { return new Offer(this); } } protected Offer(Builder builder) { offer_id = builder.offer_id; offer_price = builder.offer_price; delivery_list = builder.delivery_list; bid_number = builder.bid_number; more_number = builder.more_number; match_rate = builder.match_rate; is_bid = builder.is_bid; is_more = builder.is_more; is_matched = builder.is_matched; is_approved = builder.is_approved; bidder_id = builder.bidder_id; status = builder.status; winner_id = builder.winner_id; max_weight = builder.max_weight; number_of_delivery = builder.number_of_delivery; number_of_sender = builder.number_of_sender; take_over = builder.take_over; is_pack = builder.is_pack; company_id = builder.company_id; company_name = builder.company_name; company_review = builder.company_review; pack_id = builder.pack_id; pack = builder.pack; } public String getOfferId() { return offer_id; } public int getOfferPrice() { return offer_price; } // 後は省略 }
Doneクラスは次のようにします。
public class Done extends Offer{ private final String done_id; private final boolean is_canceled; public static class Builder extends Offer.Builder<Builder> { //必須パラメーター private String done_id; private boolean is_canceled; /** * @param offer_id * @param offer_price * @param delivery_list */ public Builder(String offer_id, int offer_price, ArrayList<Delivery> delivery_list) { super(offer_id, offer_price, delivery_list); } public Builder Done(String done_id, boolean is_canceled) { this.done_id = done_id; this.is_canceled = is_canceled; return this; } public Done build() { return new Done(this); } } protected Done(Builder builder) { super(builder); done_id = builder.done_id; is_canceled = builder.is_canceled; } public String getDone_id(){ return done_id; } }
いやー、こういうことを考える、頭の良い人がいるもんですね!!
パチパチパチパチ
Doneをインスタンスにする場合は、次のようにnewします。
Done done = new Done.Builder(offer_id, offer_price, delivery_list) .winner_id(winner_id) .number_of_delivery(receiver_number) .number_of_sender(sender_number) .max_weight(max_weight) .take_over(take_over) .is_pack(is_pack) .pack_id(getPackId(data, context)) .pack(pack) .Done(done_id, false) .build();