| 著作一覧 |
えらく梃子摺った。
public class FooSet {
List<Param> params = new ArrayList<Param>();
public Param add(Foo f) {
Param p = new Param(f);
params.add(p);
return p;
}
public Param add(Param p) {
Param op = (Param)p.clone();
params.add(op);
return op;
}
public Param findByName(String s) {
for (Param p : params) {
if (s.equals(p.getFoo().getName())) {
return p;
}
}
return null;
}
public class Param implements Cloneable {
Foo foo; // Fooはイミュータブル。
Param(Foo f) {
foo = f;
}
public Object clone() {
return super.clone();
}
public String bar() {
return foo.bar(this);
}
public Foo getFoo() {
return foo;
}
...
}
}
public class Foo {
String name;
public Foo(String initName) {
name = initName;
}
public String getName() {
return name;
}
public String bar(FooSet.Param p) {
....
return barResult;
}
}
というような感じ。FooSet.ParamはFooの入れ物兼Foo用のデータの提供/保持者、Fooはストラテジ。で、たまたま特殊なFooが必要となった。
public FooSet {
public Param {
...
public Param find(String key) { // 追加
return findByName(key);
}
}
}
public class SpecialFoo extends Foo {
public SpecialFoo(String name) {
super(name);
}
public String getData(FooSet.Param p) {
StringBuilder sb = new StringBuilder();
FooSet.Param o = p.find("BAR");
if (o != null) {
sb.append(o.bar(p));
}
sb.append(super.bar(p));
return new String(sb);
}
}
こんなのも作る。
public class FooSetTest extends TestCase {
// 追加
public void specialFooTest() throws Exception {
FooSet f = new FooSet();
f.add(new Foo("BAR"));
f.add(new SpecialFoo("BAZ"));
FooSet.Param p = f.findBy("BAZ");
assertEqulas("BARRRRBAZZZZ", p.getData());
}
}
すべてはうまく行くかのように見える。でも、うまく行かない。
次のように修正。
public class FooSet {
...
public Param add(Param p) {
Param np = new Param(p);
params.add(np);
return np;
}
...
public class Param {
...
Param(Param p) { // 追加
foo = p.foo;
}
// clone()は削除だ。
}
}
数の悪戯だろうと思ったが、試してみた。
if ARGV.length != 1
puts 'usage: ruby montyhall.rb count'
exit(1)
end
class Gamer
def initialize()
@win = 0
@door = [false, false, false]
@door[rand(3)] = true
end
attr_reader :win
end
class NoMover < Gamer
def play()
@select = rand(3)
@win += 1 if @door[@select]
end
end
class Mover < Gamer
def play()
@selection = rand(3)
open = next_number(@selection)
if !@door[@selection]
if @door[open]
open = next_number(open)
end
end
new_selection = next_number(@selection)
if new_selection == open
new_selection = next_number(new_selection)
end
@win += 1 if @door[new_selection]
end
private
def next_number(n)
(n + 1) % 3
end
end
def show(title, player)
(1...ARGV[0].to_i).each do |x|
player.play()
end
puts "#{title} won #{player.win} times."
end
show("no-mover", NoMover.new())
show("mover", Mover.new())
とりあえず100000回やりゃいいだろう。
c:\home\arton\test>ruby montyhall.rb 100000 no-mover won 33554 times. mover won 66698 times.
まじですか!
と、落ち着いて考えればMover#playにプログラムしてる通りじゃん。なんかごちゃごちゃ書いているが結局これってこういうことだな。
def play()
@select = rand(3)
@win += 1 if !@door[@select]
end
ジェズイットを見習え |