在回答之前我想说的是,策略模式及其派生的想法是利用dynamic dispatch,通过这种方式而不是手动管理条件逻辑来在代码中进行行为参数化,留下选择运行时的多态/条件行为。 IMO 策略模式是多态的最基本、最实用的形式。动态类型语言使用鸭子类型来实现,但想法是一样的。
您在这里通过利用鸭子类型来使用某种策略模式,我也需要添加它,因为问题中有一个typescript 标记(实际上使用 ES6 添加的 typescript 和 class 关键字没有改变 javascript 的性质,这是一种使用 protoypal 继承的语言,但是如果我们用这种语法糖来考虑 GoF,我需要添加这个)。
我在这里看到了一些问题。第一个是是否值得努力,因为您可以直接使用axios.get(url).then(...) 或fetch(url).then(...),我的意思是在这种情况下没有真正的多态行为,这里的变化或条件行为只是http客户端和次要方法(httpClient.get/x/y/z().then() to httpClient.url().then()),从这个角度来看,如果您的代码只保留单个方法也看起来像command pattern,这意味着只使用 lambda 函数。但是,如果您的目的是创建一个库,并且您的具体类将成为 http 客户端多个方法之上的包装器,然后为用户提供选择,那么它会更好。所以你的混凝土将是包装器。
一些 GoF 方法实际上是包装器,它们的区别在于它们的 intents,实际上 Facade 在这里就足够了。
使用经典继承和静态类型,使用策略/策略模式的想法可能如下:
客户端/驱动类是:
class Client {
fetchPolicy = PolicyFactory.getFetchPolicy('axios');
data = new Fetcher().fetchSomeData(fetchPolicy, 'https://jsonplaceholder.typicode.com/todos/1');
}
一个选择具体实现的基本工厂类:
class PolicyFactory {
const httpClients = {
axios: new MyHttpAxios(),
fetch: new MyHttpFetch(),
};
public static getFetchPolicy(policyType: string): FetchPolicy {
return Object.keys(httpClients).find(key => key === policyType);
}
}
这实际上是不必要的,只需使用httpClients['axios'] with httpClients object/map 即可。
参数化行为:
interface FetchPolicy {
get(url: string): any;
}
class MyHttpAxios implements FetchPolicy {
async get(url) {
const response = await this.axiosGet(url);
return response.data;
}
private axiosGet(url) {
axios // Since it is global use directly, or if you don't pass as a parameter in the client
.get(url)
.then(response => response)
.then(json => console.log(json));
}
}
class MyHttpFetch implements FetchPolicy {
async get(url) {
const response = await this.fetch(url).then(/*...*/);
return response.json();
}
}
这也与您的代码大致相似。
虽然这样说,但您可以只使用 lambdas 来提供这种抽象:
const fetch = require('node-fetch');
const axios = require('axios');
((url, httpClientFn, transformFn) => {
return httpClientFn(url).then(response => transformFn(response))
})("http://...", url => axios.get(url), response => console.log(response));
//somewhere in other clients which use the fetch
((url, httpClientFn, transformFn) => {
return httpClientFn(url).then(response => transformFn(response))
})("http://...", url => fetch.url(url), response => console.log(response));