「面向介面程式設計」不只是口號,而是為了可維護性與可擴展性。本文透過登入功能實例,層層剖析從「硬編碼具體類」→「工廠模式」→「依賴注入」的演進邏輯,並結合 Spring 配置示範鬆耦合實踐。
若類別 A 直接 new B(),則 A 緊耦合 B。業務變更需改用 C 時,必須修改 A 原始碼並重新編譯——大型系統代價極高。介面打破具體依賴:
interface IUserDao {
void insertUser();
boolean getUserByName(String name);
}
實作類別 UserDaoImp 實作介面,上層只依賴 IUserDao,變更實作無需動上層代碼。
abstract class DaoBase {
private User user;
public User getUser() { return user; }
public void setUser(User user) { this.user = user; }
}
class UserDaoImp extends DaoBase implements IUserDao {
public void insertUser() {
User user = new User();
user.setAge(23); user.setName("hth"); user.setPassword("123456");
setUser(user);
}
public boolean getUserByName(String name) {
insertUser();
return getUser().getName().equals(name);
}
}
// 為 Spring 注入準備的裝飾類
class UserDaoDeco extends UserDaoImp {}
interface IServiceFactory {
UserService getUserService();
// 其他 service getter...
}
class ServiceFactory implements IServiceFactory {
private UserDaoDeco userDaoDeco; // Spring 注入
public void setUserDaoDeco(UserDaoDeco udd) { this.userDaoDeco = udd; }
public UserService getUserService() {
return new UserServiceImp(userDaoDeco);
}
}
Action 僅注入 IServiceFactory,透過工廠取得 Service,Action 與具體 Service 實作解耦。
<bean id="userDaoDeco" class="com.ssh2demo.dao.UserDaoDeco"/>
<bean id="serviceFactory" class="com.ssh2demo.service.ServiceFactory">
<property name="userDaoDeco"><ref bean="userDaoDeco"/></property>
</bean>
<bean id="loginAction" class="com.ssh2demo.struts2.LoginAction" singleton="false">
<property name="service"><ref bean="serviceFactory"/></property>
</bean>
userDaoDeco 實例由 Spring 管理serviceFactory 透過 setter 注入 userDaoDecologinAction 注入 serviceFactory(介面型別),完全不關心具體實作類別像中空球體,Setter 是小孔。配置文件決定往裡塞什麼:要 UserDaoImp 就注入它,要換 MockUserDao 測試也只改配置。控制反轉 (IoC) 將「建立依賴關係」的控制權從類別內部移至外部容器。
這就是面向介面程式設計的精髓:依賴抽象,不依賴具體。