はじめに
まあ、同じアドベントカレンダーに、「真面目」なアルゴリズム開発とその実装とパフォーマンス改善の話が載っている中でこんな記事を上げるのは申し訳ない、と思いつつ、いやいや、こういうのはハードルを上げると衰退するんだよな、などと考えてそこそこヘタレた記事を量産していく所存であります。(え)
SecondMax実装したよー。
というわけでこんな実装にしてみました。
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;
public class SecondMaxImpl0 implements SecondMax {
private int list_size = 5;
@Override
public void setListSize(int list_size) {
this.list_size = list_size;
}
@Override
public int getListSize() {
return list_size;
}
@Override
public SecondMaxResult doSecondMax(Scanner scanner) {
List<Integer> list = new ArrayList<>();
for ( int index = 0 ; index < list_size ; index++ ) {
list.add(scanner.nextInt());
}
list.sort(Comparator.reverseOrder());
return new SecondMaxResult(
list.get(0).intValue() == list.get(1).intValue(),
list.get(1)
);
}
}
まあ分かりにくいかな…。必要なクラスとしてこういうのも書きました。
public record SecondMaxResult(boolean maxRepeated,int secondMax) {
}
あと
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Scanner;
public class SecondMaxRunner {
public static void main(String[] args) {
try {
Class<?> secondMax = Class.forName("SecondMaxImpl" + args[0]);
Constructor<?> secondMaxConstructor = secondMax.getConstructor();
SecondMax secondMaxInstance = (StoiuecondMax) secondMaxConstructor.newInstance();
secondMaxInstance.setListSize(Integer.parseInt(args[1]));
try ( Scanner scanner = new Scanner(System.in) ) {
SecondMaxResult result = secondMaxInstance.doSecondMax(scanner);
if ( result.maxRepeated() ) {
System.out.println("At least two same maximum numbers found. No second maximum.");
} else {
System.out.println("The second maximum number in the sequence is %d".formatted(result.secondMax()));
}
}
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
もういっちょ。
import java.util.Scanner;
public interface SecondMax {
public void setListSize(int list_size);
public int getListSize();
public SecondMaxResult doSecondMax(Scanner scanner);
}
これだけあればコンパイルは通ります。実行は
% java SecondMaxRunner 0 5
1
2
3
4
5
ってやると、
The second maximum number in the sequence is 4
と出力するわけですね。
で、SecondMaxImple<n> というクラスを作って同じところに置いてあげれば、
% echo 1 2 3 4 5 | java SecondMaxRunner 0 5
The second maximum number in the sequence is 4
% echo 1 2 3 4 5 | java SecondMaxRunner 1 5
The second maximum number in the sequence is 4
% echo 1 2 3 4 5 | java SecondMaxRunner 2 5
The second maximum number in the sequence is 4
というように使えるわけです。SecondMaxImpl1クラスやSecondMaxImpl2クラスを書けばこうやって差し替えながら実行させることができるようになるというわけですね。
もちろんインターフェースを経由するオーバーヘッドや、Runnerが指定クラスを読み込んで使えるようにするための準備に掛かる工数が追加されたりはするわけですが、SecondMaxRunnerを再コンパイルする必要がないみたいなメリットもありますので、そういう話です。
まあ、これ見て興味が湧いたら、「フレームワークの世界」に踏み出してみるのも良いかもしれませんよ。