在开发企业级网络管理应用时,经常会遇到不同设备类型需要统一管理的情况。比如一个系统要同时处理路由器、交换机和防火墙的配置下发,这些设备有共性,也有各自的特殊逻辑。这时候如果只用类继承,代码容易变得僵硬;而单独使用工厂模式,又可能失去结构上的统一。把两者结合起来,反而能发挥出更大的灵活性。
从一个实际场景说起
假设你在写一个自动配置工具,需要为不同品牌的路由器生成配置脚本。华为、华三和思科的命令语法不一样,但它们都属于“路由器”这个大类。你可以定义一个基类 Router,封装通用行为,比如连接设备、保存配置、测试连通性等。
class Router {
constructor(ip, username, password) {
this.ip = ip;
this.username = username;
this.password = password;
}
connect() {
console.log(`连接到 ${this.ip}`);
}
saveConfig() {
throw new Error('子类必须实现 saveConfig');
}
}
然后通过类继承,让具体设备类型去实现自己的逻辑:
class HuaweiRouter extends Router {
saveConfig() {
return 'save';
}
}
class CiscoRouter extends Router {
saveConfig() {
return 'write memory';
}
}
问题来了:怎么创建合适的对象?
当用户上传一批设备信息,你怎么知道该实例化哪个类?如果到处写 new HuaweiRouter(...) 或 new CiscoRouter(...),一旦新增品牌就得改很多地方。这时候引入工厂模式就顺理成章了。
写一个工厂函数,根据输入参数决定返回哪种路由器实例:
class RouterFactory {
static create(type, ip, username, password) {
switch(type.toLowerCase()) {
case 'huawei':
return new HuaweiRouter(ip, username, password);
case 'cisco':
return new CiscoRouter(ip, username, password);
case 'h3c':
return new H3CRouter(ip, username, password);
default:
throw new Error(`不支持的设备类型: ${type}`);
}
}
}
这样一来,主流程只需要关心“我要一个路由器”,不用管具体是谁。调用方式变得干净:
const router = RouterFactory.create('cisco', '192.168.1.1', 'admin', 'pass');
router.connect();
console.log(router.saveConfig()); // 输出: write memory
这种搭配的好处
类继承保证了所有设备都有统一的接口,工厂模式则隐藏了创建细节。新增一种设备时,只需新增一个子类并修改工厂中的分支,其他代码几乎不用动。维护起来轻松不少。
在网络自动化脚本中,这种组合特别实用。比如你写的部署工具今天支持三种设备,半年后扩展到八种,只要工厂和继承体系设计得好,扩展就像插拔模块一样简单。
更重要的是,团队协作时,新人不需要记住每个类怎么用,只要知道从工厂拿对象就行。降低了出错概率,也减少了沟通成本。