模板方法模式实战:contacts 的 Base 类与 TYPES 注册表如何优雅扩展6家邮箱 Provider

发布时间:2026/8/26 20:02:53
模板方法模式实战:contacts 的 Base 类与 TYPES 注册表如何优雅扩展6家邮箱 Provider 模板方法模式实战contacts 的 Base 类与 TYPES 注册表如何优雅扩展6家邮箱 Provider【免费下载链接】contactsA universal interface to import email contacts from various providers including Yahoo, Gmail, Hotmail, AOL and Plaxo.项目地址: https://gitcode.com/gh_mirrors/contacts23/contactscontacts 是一个 Ruby 开源库提供统一的接口从 Yahoo、Gmail、Hotmail、AOL、Plaxo、Mail.ru 等邮箱服务商抓取联系人列表。它用最经典的模板方法模式把登录 → 请求 → 解析的公共流程沉淀在 Base 父类中各 Provider 只需实现自己的差异步骤再向 TYPES 注册表登记一行代码即可接入。本文带你拆解这套设计并手把手学会新增一家邮箱 Provider。模板方法模式为什么适合多 Provider 联系人抓取抓取不同邮箱的联系人看似每家都不一样其实流程高度一致建立连接验证账号密码、拿到登录 Cookie拉取联系人请求地址簿页面或接口解析数据把 HTML、JSON、CSV、XML 统一成[姓名, 邮箱]格式模板方法模式正是为这种骨架相同、细节不同的场景而生父类Contacts::Base定好流程骨架子类只填空。拆解 Base 父类流程骨架长什么样核心骨架在 lib/contacts/base.rb 中initialize(login, password)保存凭据后自动调用connectconnect做参数校验然后交给子类的real_connect真正登录contacts检查connected?后请求contact_list_url再交给子类的parse解析私有工具方法post、get自动处理 Cookie、gzip 解压、302 跳转、open_http连接复用def connect raise AuthenticationError, ... if login.nil? || login.empty? real_connect # 子类实现各家邮箱真正的登录逻辑 end子类要做的只有两件事实现real_connect以及实现parse或干脆重写contacts。比如 lib/contacts/yahoo.rb 里的Yahoo类用post提交登录表单、检查Invalid ID or password等失败特征登录成功后把 Cookie 存进cookies即可。一个巧妙的设计是子类用类常量声明配置父类用const_get动态读取如class Yahoo Base URL http://mail.yahoo.com/ CONTACT_LIST_URL http://address.mail.yahoo.com/?... end父类的domain、contact_list_url等方法通过self.class.const_get(:URL)拿到当前子类的值无需子类写任何 getter。读懂 TYPES 注册表名称 → 类的插件式登记lib/contacts/base.rb 顶部定义了一个空哈希class Contacts TYPES {}每个 Provider 文件在末尾登记自己例如 lib/contacts/yahoo.rb、lib/contacts/hotmail.rbTYPES[:yahoo] Yahoolib/contacts.rb 依次require全部 6 个 Provider 文件加载完毕后TYPES就填满了 6 家服务。于是统一入口可以这样写Contacts.new(:gmail, login, password).contacts内部只是查一下TYPES类不存在就抛出TypeNotFound并把所有可用类型名列在报错信息里。更进一步Contacts.guess(login, password)会遍历TYPES逐个尝试登录成功的联系人全部合并返回——账号密码相同横跨多家邮箱时一个方法就能全量取回。三种使用姿势按需选择接入粒度以 examples/grab_contacts.rb 为例contacts 给了三种玩法姿势写法适用场景直接实例化子类Contacts::Yahoo.new(login, pwd).contacts明确知道目标邮箱统一入口Contacts.new(:aol, login, pwd).contacts由字符串/符号动态决定自动探测Contacts.guess(login, pwd)不知道用户用的是哪家三者返回格式完全一致[[姓名, 邮箱地址], ...]这就是模板方法模式的最大红利——调用方永远不需要关心 Provider 差异。新增一家邮箱 Provider 的三步扩展法想接入新邮箱比如某家新服务商按下面三步走建文件写子类在lib/contacts/下新建xxx.rb定义class Xxx Base实现real_connect复用父类的post/get发登录请求、判断失败特征、存cookies解析联系人实现parse(data)把响应转成[[姓名, 邮箱], ...]如 lib/contacts/mailru.rb 那样用CSV.parse或像 lib/contacts/plaxo.rb 那样解析 XML登记并加载文件末尾加TYPES[:xxx] Xxx再到 lib/contacts.rb 中加一行require xxx全程不改 Base不改入口方法符合开闭原则。值得抄进你代码库的设计亮点错误体系统一AuthenticationError/ConnectionError/TypeNotFound全部继承自ContactsError见 lib/contacts/base.rb上层只需 rescue 一个基类重试细节login方法第一次失败重试时会自动补全域名后缀兼容用户填全邮箱或只填用户名两种情况gzip 开关父类提供skip_gzip?钩子默认返回falseMail.ru 这类压缩异常的 Provider 只需覆写返回true一行搞定总结contacts 用一个不到 200 行的Base类加一个TYPES哈希就搭起了一个可扩展的邮箱 Provider 框架模板方法模式固定连接—拉取—解析骨架常量声明加const_get实现零样板配置注册表实现插件式扩展。理解了这套结构你在做任何同流程、多实现的功能多支付渠道、多对象存储、多消息队列时都能直接复用这套思路。【免费下载链接】contactsA universal interface to import email contacts from various providers including Yahoo, Gmail, Hotmail, AOL and Plaxo.项目地址: https://gitcode.com/gh_mirrors/contacts23/contacts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考