2011年8月19日金曜日

Interfaceに内部enumをつけて、そのenumが他のinterfaceを実装していて、自己満足なコードができている。

Interfaceに内部enumをつけて、そのenumが他のinterfaceを実装していて、自己満足なコードができている。


と、ツイートしたので、その自己満足なコードを晒してみる。


package orz.mikeneck.gae.slim3.model.alarm;

import java.util.Date;
import java.util.TimeZone;

import org.slim3.controller.validator.Validator;
import org.slim3.controller.validator.Validators;

import orz.mikeneck.gae.slim3.util.AttributeKeyValue;
import orz.mikeneck.gae.slim3.util.AttributeValidation;

public interface AlarmDate {

    public static final TimeZone TIME_ZONE = TimeZone.getTimeZone("Asia/Tokyo");

    public static final String KEY_YEAR = "YEAR";

    public static final String KEY_MONTH = "MONTH";

    public static final String KEY_DATE = "DATE";

    public static final String KEY_HOUR = "HOUR_OF_DAY";

    public static final String KEY_MINUTE = "MINUTE";

    public static final long MONTH_MAX = 12;

    public static final long MONTH_MIN = 1;

    public static final long DATE_MAX = 31;

    public static final long DATE_MIN = 1;

    public static final long HOUR_MAX = 23;

    public static final long HOUR_MIN = 0;

    public static final long MINUTE_MIN = 0;

    public static final long MINUTE_MAX = 55;

    public int year();

    public int month();

    public int date();

    public int hour();

    public int minute();

    public Date getCreatedAt();

    enum AttributeMapper implements AttributeKeyValue<AlarmDate>, AttributeValidation {
        ATTRIBUTE_YEAR {
            @Override
            public String key() {
                return KEY_YEAR;
            }

            @Override
            public <T> T value(AlarmDate model, Class<T> klass) {
                return klass.cast(model.year());
            }

            @Override
            public Class<?> type() {
                return Integer.class;
            }

            @Override
            public Validator[] validation(Validators valid) {
                return new Validator[] {
                    valid.required(),
                    valid.integerType()};
            }
        }, ATTRIBUTE_MONTH {
            @Override
            public String key() {
                return KEY_MONTH;
            }

            @Override
            public <T> T value(AlarmDate model, Class<T> klass) {
                return klass.cast(model.month());
            }

            @Override
            public Class<?> type() {
                return Integer.class;
            }

            @Override
            public Validator[] validation(Validators valid) {
                return new Validator[] {
                    valid.required(),
                    valid.integerType(),
                    valid.longRange(MONTH_MIN, MONTH_MAX)};
            }
        }, ATTRIBUTE_DATE {
            @Override
            public String key() {
                return KEY_DATE;
            }

            @Override
            public <T> T value(AlarmDate model, Class<T> klass) {
                return klass.cast(model.date());
            }

            @Override
            public Class<?> type() {
                return Integer.class;
            }

            @Override
            public Validator[] validation(Validators valid) {
                return new Validator[] {
                    valid.required(),
                    valid.integerType(),
                    valid.longRange(DATE_MIN, DATE_MAX)};
            }
        }, ATTRIBUTE_HOUR_OF_DAY {
            @Override
            public String key() {
                return KEY_HOUR;
            }

            @Override
            public <T> T value(AlarmDate model, Class<T> klass) {
                return klass.cast(model.hour());
            }

            @Override
            public Class<?> type() {
                return Integer.class;
            }

            @Override
            public Validator[] validation(Validators valid) {
                return new Validator[] {
                    valid.required(),
                    valid.integerType(),
                    valid.longRange(HOUR_MIN, HOUR_MAX)
                };
            }
        }, ATTRIBUTE_MINUTE {
            @Override
            public String key() {
                return KEY_MINUTE;
            }

            @Override
            public <T> T value(AlarmDate model, Class<T> klass) {
                return klass.cast(model.minute());
            }

            @Override
            public Class<?> type() {
                return Integer.class;
            }

            @Override
            public Validator[] validation(Validators valid) {
                return new Validator[] {
                    valid.required(),
                    valid.integerType(),
                    valid.longRange(MINUTE_MIN, MINUTE_MAX)
                };
            }
        };

        @Override
        abstract public String key();

        @Override
        abstract public <T> T value(AlarmDate model, Class<T> klass);

        @Override
        abstract public Class<?> type();

        @Override
        abstract public Validator[] validation(Validators valid);

        @Override
        public void validate(Validators valid) {
            valid.add(key(), validation(valid));
        }
    }
}


こやつは、Slim3のModelクラスのインターフェースなのですが、何がいいかというと、requestのマッピングとか、Validationのコードなどが劇的にキレイになる。

Mapping

package orz.mikeneck.gae.slim3.controller.alarm;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;

import orz.mikeneck.gae.slim3.model.alarm.AlarmDate;
import orz.mikeneck.gae.slim3.model.alarm.AlarmDateModel;

public class IndexController extends Controller {

    @Override
    public Navigation run() throws Exception {
        AlarmDate model = new AlarmDateModel();
        for(AlarmDate.AttributeMapper mapper : AlarmDate.AttributeMapper.values())
            request.setAttribute(mapper.key(), mapper.value(model, mapper.type()));
        return forward("index.jsp");
    }
}


Validators

package orz.mikeneck.gae.slim3.controller.alarm;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;
import org.slim3.controller.validator.Validators;

import orz.mikeneck.gae.slim3.model.alarm.AlarmDate;

public class WakeController extends Controller {

    @Override
    public Navigation run() throws Exception {
        Validators valid = new Validators(request);
        for(AlarmDate.AttributeMapper mapper : AlarmDate.AttributeMapper.values())
            mapper.validate(valid);
        return redirect(basePath);
    }
}


Validationとかの部分が二行で書けるので、コントローラーにモデルに関する複雑なことを書かんでよくなる。
まあ、もっといいやりかたがあるんだろうけど、コレが今のオレの程度…orz


0 件のコメント:

コメントを投稿