オブジェクト指向プログラミング十戒 6 シンプルなインタフェースを心掛ける


 

6 シンプルなインタフェースを心掛ける

メソッドの引数は必要最小限にとどめる。引数が少なければ試験プログラムのメソッドを呼ぶための事前設定が楽になる。かといって、グローバルな変数の参照を増やしては意味がない。

Information.java
public class Information { private int data1; private int data2; private int data3; private int data4; public Information() {} public Information(int a, int b, int c, int d) { data1 = a; data2 = b; data3 = c; data4 = d; } // 略 }

コンストラクターでフィールドに初期値を与えています。設定するフィールドが多いとコンストラクターの引数が多くなってしまいます。


Information.java
public class Information { public int data1; public int data2; public int data3; public int data4; public Information() {} // 略 }

コンストラクターでは初期値を与えず、フィールドを public にして自由に参照できるようにしています。しかし、これではフィールドの型はもちろん名前も変更することが難しくなります。

Information.java
public class Information { private int data1; private int data2; private int data3; private int data4; public Information() {} public void setData1(int v) { data1 = v; } public void setData2(int v) { data2 = v; } // 略 }

フィールドに値を設定するメソッドを用意します。これにより必要な値だけ設定でき、コンストラクターなどの引数を少なくできます。


フィールドに値を設定するメソッドが void 型の場合、プログラムの記述量が多くなりがちである。メソッドチェーンを使用することで記述を少なくできる。

Information.java
public class Information { private int data1; private int data2; private int data3; private int data4; public Information() {} public void setData1(int v) { data1 = v; } public void setData2(int v) { data2 = v; } // 略 }
Process.java
public class Process { public doProc() { Information info = new Information(); info.setData1(10); info.setData2(25); info.setData3(60); // 略 } // 略 }

フィールドに値を設定するメソッドを一つひとつ呼び出す必要があります。

Information.java
public class Information { private int data1; private int data2; private int data3; private int data4; public Information() {} public Information setData1(int v) { data1 = v; return this; } public Information setData2(int v) { data2 = v; return this; } // 略 }
Process.java
public class Process { public doProc() { Information info = new Information(); info.setData1(10).setData2(25).setData3(60); // 略 } // 略 }

メソッドチェーンを使用することによって、単一の文で同一オブジェクトの複数のメソッドを呼出すことができます。


同種類の引数を複数設定しようとするとき、引数の数を変えたメソッドをオーバーロードするのではなく可変長引数とする。

Url.java
public class Url { public String makeUrl(String scheme, String p1) { return scheme + "://" + p1; } public String makeUrl(String scheme, String p1, String p2) { return makeUrl(scheme, p1) + "/" + p2; } public String makeUrl(String scheme, String p1, String p2, String p3) { return makeUrl(scheme, p1, p2) + "/" + p3; } }

同様の処理をするメソッドを引数の数を替えて用意しました。

Url.java
public class Url { public String makeUrl(String scheme, String... path) { String url = ""; for(String p : path) { url += "/" + p; } return scheme + ":/" + url; } }

複数の同種の引数は可変長引数として記述できます。これにより引数の数に合わせて複数のメソッドを用意する必要がなくなります。


インスタンスごとにすべての情報をいちいち設定するのではなく、先に作成したインスタンスをコピーして次のインスタンスを作成すると、プログラムの記述量が少なくなる。

Value.java
public class Value { private int a, b, c, d; public Value setA(int v) { a = v; return this; } public Value setB(int v) { b = v; return this; } public Value setC(int v) { c = v; return this; } public Value setD(int v) { d = v; return this; } }
Process.java
public class Process { public void doProc() { Value val1 = new Value(); val1.setA(1).setB(5).setC(13).setD(21); Value val2 = new Value(); val2.setA(1).setB(7).setC(13).setD(21); } }

多数の情報を設定しなければなりません。ほとんど同じ情報だとしても、複数のインスタンスを作成する場合はそれぞれに設定する必要があります。

Value.java
public class Value implements Cloneable { private int a, b, c, d; public Value setA(int v) { a = v; return this; } public Value setB(int v) { b = v; return this; } public Value setC(int v) { c = v; return this; } public Value setD(int v) { d = v; return this; } public Value createClone() { Value p = null; try { p = (Value) clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return p; } }
Process.java
public class Process { public void doProc() { Value val1 = new Value(); val1.setA(1).setB(5).setC(13).setD(21); Value val2 = val1.createClone().setB(7); } }

設定しなければならない情報が多数あっても、既存のインスタンスのコピーを作成し、異なる情報だけ設定しなおします。


引数の値がメソッド内で変更されないのなら final とする。

Print.java
public class Print { public void print(String title, int val) { System.out.println(title + ":" + val); } }

引数の値をメソッド内で変更することができます。

Print.java
public class Print { public void print(final String title, final int val) { System.out.println(title + ":" + val); } }

引数の値をメソッド内で変更するような記述をするとエラーになります。