第 25 課以「將所有 private 改為 public 程序還能工作嗎?」為切入點,揭示信息隱藏的本質非安全而是應對變化。通過復數類「直角坐標 vs 極坐標」兩種實現的對比,展示抽象接口屏蔽結構性變化;引入橋梁模式徹底解耦接口與實現;並對比 Java 無頭文件優勢與 C++ 頭文件帶來的重編譯負擔。
public class Complex {
private double x, y; // 實部、虛部
public Complex(double x, double y) { this.x = x; this.y = y; }
public double real() { return x; }
public double imaginary() { return y; }
public double modulus() { return Math.hypot(x, y); }
public double argument() { return Math.atan2(y, x); }
public Complex add(Complex o) { return new Complex(x + o.x, y + o.y); }
public Complex multiply(Complex o) {
return new Complex(x * o.x - y * o.y, x * o.y + y * o.x);
}
}
public class Complex {
private double r, theta; // 模、輻角
public Complex(double x, double y) {
r = Math.hypot(x, y);
theta = Math.atan2(y, x);
}
public double real() { return r * Math.cos(theta); }
public double imaginary() { return r * Math.sin(theta); }
public double modulus() { return r; }
public double argument() { return theta; }
public Complex add(Complex o) {
return new Complex(r * Math.cos(theta) + o.r * Math.cos(o.theta),
r * Math.sin(theta) + o.r * Math.sin(o.theta));
}
public Complex multiply(Complex o) {
Complex p = new Complex(0, 0);
p.r = r * o.r;
p.theta = theta + o.theta;
return p;
}
}
結論:接口相同,實現截然不同。客戶代碼零修改即可切換實現。直角坐標利於加減,極坐標利於乘除冪根。
// 接口
public interface ComplexImpl {
double real(); double imaginary(); double modulus(); double argument();
Complex add(Complex o); Complex multiply(Complex o);
}
// 直角坐標實現
public class ComplexCartesianImpl implements ComplexImpl { ... }
// 極坐標實現
public class ComplexPolarImpl implements ComplexImpl { ... }
// 橋梁類
public class Complex {
private ComplexImpl impl;
public Complex(double x, double y) {
impl = new ComplexCartesianImpl(x, y); // 或 PolarImpl
}
// 委託所有操作
public double real() { return impl.real(); }
...
}
優勢:接口與實現完全分離,可編譯期或運行期切換實現,增強適應力、擴展性。代價:增加複雜度與間接調用開銷,酌情使用避免過度設計。
新增運算(如冪、開方)只需在接口添加方法,不修改現有方法簽名,不傷及舊客戶代碼——體現開放封閉原則。