💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
### Introduce Foreign Method(引入外加函数) 你所使用的server class需要一个额外函数,但你无法修改这个class。 在client class中建立一个函数,并以一个server class实体作为第一引数(argument) : ~~~ Date newStart = new Date (previousEnd.getYear(), previousEnd.getMonth(), previousEnd.getDate() + 1); ~~~ ~~~ Date newStart = nextDay(previousEnd); private static Date nextDay(Date arg) { return new Date (arg.getYear(),arg.getMonth(), arg.getDate() + 1); } ~~~ **动机(Motivation)** 这种事情发生过太多次了:你正在使用一个class,它真的很好,为你提供了你想要的所有服务。而后,你又需要一项新服务,这个class却无法供应。于是你开始咒骂:「为什么不能做这件事?」如果可以修改源码,你便可以自行添加一个新函数; 如果不能,你就得在客户端编码,补足你要的那个函数。 如果client class只使用这项功能一次,那么额外编码工作没什么大不了,甚至可能根本不需要原本提供服务的那个class。然而如果你需要多次使用这个函数,你就得不断重复这些代码。还记得吗,重复的代码是软件万恶之源。这些重复性代码应该被抽出来放进同一个函数中。进行本项重构时,如果你以外加函数实现一项功能, 那就是一个明确信号:这个函数原本应该在提供服务的(server)class中加以实现。 如果你发现自己为一个server class建立了大量外加函数,或如果你发现有许多classes都需要同样的外加函数,你就不应该再使用本项重构,而应该使用 Introduce Local Extension。 但是不要忘记:外加函数终归是权宜之计。如果有可能,你仍然应该将这些函数搬移到它们的理想家园。如果代码拥有权(code ownership)是个需要考量的问题, 就把外加函数交给server class的拥有者,请他帮你在此server class中实现这个函数。 **作法(Mechanics)** - 在client class中建立一个函数,用来提供你需要的功能。 - 这个函数不应该取用client class的任何特性。如果它需要一个值,把该值当作参数传给它。 - 以server class实体作为该函数的第一个参数。 - 将该函数注释为:「外加函数(foreign method),应在server class实现。」 - 这么一来,将来如果有机会将外加函数搬移到server class中,你便可以轻松找出这些外加函数。 **范例(Examples)** 程序中,我需要跨过一个收费周期(billing period)。原本代码像这样: ~~~ Date newStart = new Date (previousEnd.getYear(), previousEnd.getMonth(), previousEnd.getDate() + 1); ~~~ 我可以将赋值运算右侧代码提炼到一个独立函数中。这个函数就是Date class的一个外加函数: ~~~ Date newStart = nextDay(previousEnd); private static Date nextDay(Date arg) { // foreign method, should be on date return new Date (arg.getYear(),arg.getMonth(), arg.getDate() + 1); } ~~~