「第9回 オフラインリアルタイムどう書く」別解(Java)

「第9回 オフラインリアルタイムどう書く」へなちょこ解答(Java)(http://d.hatena.ne.jp/torazuka/20130407/yhpg)の別解を書きました。

以前はどう書くの問題を見た瞬間に、あまり何も考えずに個々の要素を表わすクラスを作り始めていたのですが、最近そういうやり方をしなくなりました。

そこで試しに、昔のやり方で昨日の解答を書き改めてみました。

例のバス代の問題です。

解答

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

class Paseenger {
	Age age;
	Kind kind;

	public Paseenger(final String str) {
		age = createAge(str.charAt(0));
		kind = createKind(str.charAt(1));
	}

	private Age createAge(final char c) {
		AgeKey key = AgeKey.valueOf(String.valueOf(c));
		return key.make();
	}

	private Kind createKind(final char c) {
		KindKey key = KindKey.valueOf(String.valueOf(c));
		return key.make();
	}

	public void lineUp(final BusfeeEx bf) {
		age.lineUp(this, bf);
	}

	public int getFee(final int base) {
		int tmp = age.getFee(base);
		return kind.discount(tmp);
	}
}

abstract class Age {
	abstract int getFee(final int base);

	abstract void lineUp(final Paseenger p, final BusfeeEx bf);
}

class Adult extends Age {
	@Override
	public int getFee(final int base) {
		return base;
	}

	@Override
	void lineUp(final Paseenger p, final BusfeeEx bf) {
		bf.pushPassenger(this, p);
	}
}

class Child extends Age {
	@Override
	public int getFee(final int base) {
		return BusfeeEx.getHalf(base);
	}

	@Override
	void lineUp(final Paseenger p, final BusfeeEx bf) {
		bf.pushPassenger(this, p);
	}
}

class Infant extends Age {
	@Override
	public int getFee(final int base) {
		return BusfeeEx.getHalf(base);
	}

	@Override
	void lineUp(final Paseenger p, final BusfeeEx bf) {
		p.kind.lineUp(p, bf);
	}
}

enum AgeKey {
	A {
		@Override
		Age make() {
			return new Adult();
		}
	},
	C {
		@Override
		Age make() {
			return new Child();
		}
	},
	I {
		@Override
		Age make() {
			return new Infant();
		}
	};

	abstract Age make();
}

abstract class Kind {
	abstract int discount(final int original);

	abstract void lineUp(final Paseenger p, final BusfeeEx bf);
}

class Normal extends Kind {
	@Override
	public int discount(final int original) {
		return original;
	}

	@Override
	void lineUp(final Paseenger p, final BusfeeEx bf) {
		bf.pushPassenger(this, p);
	}
}

class Pass extends Kind {
	@Override
	public int discount(final int original) {
		return 0;
	}

	@Override
	void lineUp(final Paseenger p, final BusfeeEx bf) {
		bf.pushPassenger(this, p);
	}
}

class Welfare extends Kind {
	@Override
	public int discount(final int original) {
		return BusfeeEx.getHalf(original);
	}

	@Override
	void lineUp(final Paseenger p, final BusfeeEx bf) {
		bf.pushPassenger(this, p);
	}
}

enum KindKey {
	n {
		@Override
		Kind make() {
			return new Normal();
		}
	},
	p {
		@Override
		Kind make() {
			return new Pass();
		}
	},
	w {
		@Override
		Kind make() {
			return new Welfare();
		}
	};

	abstract Kind make();
}

/**
 * 問題: http://nabetani.sakura.ne.jp/hena/ord9busfare/
 */
public class BusfeeEx {

	List<Paseenger> adults = new ArrayList<>();
	List<Paseenger> children = new ArrayList<>();
	List<Paseenger> infantNormal = new ArrayList<>();
	List<Paseenger> infantPass = new ArrayList<>();
	List<Paseenger> infantWelfare = new ArrayList<>();

	static int getHalf(final int original) {
		int tmp = original / 2;
		if (tmp % 10 == 0) {
			return tmp;
		}
		return tmp + (10 - tmp % 10);
	}

	List<Paseenger> createPassengers(final String str) {
		List<String> tmp = Arrays.asList(str.split(","));
		List<Paseenger> result = new ArrayList<>();
		for (String each : tmp) {
			result.add(new Paseenger(each));
		}
		return result;
	}

	public void pushPassenger(final Adult age, final Paseenger p) {
		adults.add(p);
	}

	public void pushPassenger(final Child age, final Paseenger p) {
		children.add(p);
	}

	public void pushPassenger(final Normal kind, final Paseenger p) {
		infantNormal.add(p);
	}

	public void pushPassenger(final Pass kind, final Paseenger p) {
		infantPass.add(p);
	}

	public void pushPassenger(final Welfare kind, final Paseenger p) {
		infantWelfare.add(p);
	}

	public String solve(final String input) {
		int base = Integer.valueOf(input.split(":")[0]);
		List<Paseenger> passengers = createPassengers(input.split(":")[1]);
		for (Paseenger each : passengers) {
			each.lineUp(this);
		}

		int freeLimit = adults.size() * 2;
		freeLimit = discount(infantNormal, freeLimit);
		discount(infantWelfare, freeLimit);

		passengers.clear();
		passengers.addAll(adults);
		passengers.addAll(children);
		passengers.addAll(infantNormal);
		passengers.addAll(infantPass);
		passengers.addAll(infantWelfare);

		int result = 0;
		for (Paseenger each : passengers) {
			result += each.getFee(base);
		}
		return String.valueOf(result);
	}

	private int discount(List<Paseenger> list, final int freeLimit) {
		int result = freeLimit;
		Iterator<Paseenger> iterator = list.iterator();
		while (iterator.hasNext()) {
			iterator.next();
			if (0 < result) {
				iterator.remove();
				result--;
			}
		}
		return result;
	}
}

結論: アカン…

ちなみに、ダブルディスパッチは、結城先生のデザパタ本のVisitor章で理解したつもりになっていますが、おかしい等のツッコミありましたらよろしくお願いします。