简体   繁体   English

这是策略模式吗

[英]Is this strategy pattern

To move from one http client to another (same concept can be applied to log libs, db's) I implemented this solution but I am not sure if it's a pattern in OOP world.为了从一个 http 客户端移动到另一个客户端(相同的概念可以应用于日志库、数据库),我实现了这个解决方案,但我不确定它是否是 OOP 世界中的一种模式。 After looking at some it kinda looks like strategy pattern or repository pattern.在看了一些之后,它看起来有点像策略模式或存储库模式。 But what I understood from repository pattern it is only restricted to data access functionality.但是我从存储库模式中了解到,它仅限于数据访问功能。 However same concept can be applied logging libs, http clients or email client etc.然而,同样的概念可以应用于日志库、http 客户端或 email 客户端等。

Here is my implementation of something that I don't know the name: ( =D )这是我不知道名称的实现:( =D )

const fetch = require('node-fetch');
const axios = require('axios');
class MyHttpAxios {
  constructor(axios) {
    this.axios = axios;
  }

  async get(url) {
    const response = await this.axios.get(url);
    return response.data;
  }
}

class MyHttpFetch {
  constructor(fetch) {
    this.fetch = fetch;
  }
  async get(url) {
    const response = await this.fetch(url);
    return response.json();
  }
}

const httpClients = {
  axios: new MyHttpAxios(axios),
  fetch: new MyHttpFetch(fetch),
};

const client = httpClients['axios'];
client
  .get('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => response)
  .then(json => console.log(json));

Before the answer I would like to say that, the idea in Strategy pattern and its derivations is to take the advantage of dynamic dispatch and in this way instead of manually managing conditional logic to make behavior parameterization in the code, leaving the selection of polymorphic/conditional behavior to the runtime.在回答之前我想说,策略模式及其派生的思想是利用dynamic dispatch的优势,通过这种方式而不是手动管理条件逻辑在代码中进行行为参数化,留下多态/多态的选择。运行时的条件行为。 IMO strategy pattern is the most basic and practical form of polymorphism. IMO 策略模式是多态的最基本和最实用的形式。 Dynamic-typed languages does it with duck typing but the idea is same.动态类型语言使用鸭子类型来做到这一点,但想法是一样的。

You are using some kind of strategy pattern here by taking the advantage of duck typing which I needed to add this also, because there is a typescript tag in the question (Actually typescript and class keyword added with ES6 doesn't change the nature of javascript which is a language using protoypal inheritance, but If we think in terms of GoF with this syntactical sugar I needed to add this). You are using some kind of strategy pattern here by taking the advantage of duck typing which I needed to add this also, because there is a typescript tag in the question (Actually typescript and class keyword added with ES6 doesn't change the nature of javascript这是一种使用 protoypal inheritance 的语言,但如果我们用这种语法糖来考虑 GoF,我需要添加这个)。

I see a few issues here.我在这里看到了一些问题。 First one is whether is it worth the effort or not because you could directly use axios.get(url).then(...) or fetch(url).then(...) which I mean there is no really a polymorphic behavior in this case, what change or the conditional behaviour here is just the http client and minor method( httpClient.get/x/y/z().then() to httpClient.url().then() ) and from this perspective if your code would only keep single method also look like a command pattern which implies the usage of just lambda functions.第一个是是否值得努力,因为您可以直接使用axios.get(url).then(...)fetch(url).then(...) ,我的意思是没有真正的多态在这种情况下的行为,这里的变化或条件行为只是 http 客户端和次要方法( httpClient.get/x/y/z().then() to httpClient.url().then() )和从这个如果您的代码只保留单个方法,那么它看起来也像一个command pattern ,这意味着只使用 lambda 函数。 However if your purpose is to create a library and if your concrete classes will be a wrapper above http clients' multiple methods and then provide users a selection then it would be finer.但是,如果您的目的是创建一个库,并且您的具体类将成为 http 客户端的多种方法之上的包装器,然后为用户提供选择,那么它会更好。 So your concretes will be wrappers.所以你的混凝土将是包装材料。

Some of the GoF methods are actually wrappers and what distinguish them is their intent s and actually a Facade would be enough here.一些 GoF 方法实际上是包装器,它们的区别在于它们的intent ,实际上Facade在这里就足够了。

With classical inheritance and static typing, the idea to use Strategy/Policy pattern is could be below:使用经典的 inheritance 和 static 类型,使用策略/策略模式的想法可能如下:

The client/driver class is:客户端/驱动程序 class 是:

class Client {
    fetchPolicy = PolicyFactory.getFetchPolicy('axios');
    data = new Fetcher().fetchSomeData(fetchPolicy, 'https://jsonplaceholder.typicode.com/todos/1');
}

A basic factory class to choose concrete implementation: A基本厂class选择具体实现:

class PolicyFactory {
    const httpClients = {
      axios: new MyHttpAxios(),
      fetch: new MyHttpFetch(),
    };
    public static getFetchPolicy(policyType: string): FetchPolicy {
       return Object.keys(httpClients).find(key => key === policyType);
    }
}

Which is actually unnecessary and just using httpClients['axios'] with httpClients object/map does above.这实际上是不必要的,只需将httpClients['axios'] with httpClients object/map

Parameterized behaviour:参数化行为:

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();
  }
}

Which also roughly similar to your code.这也与您的代码大致相似。

While said this you could just use lambdas to provide this kind of abstraction:虽然这么说你可以只使用 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));
 

I think that is more an array of Classes than a true Strategy Pattern.我认为这更像是一个类数组,而不是真正的策略模式。 Should that, what you have created, be considered a pattern?那,你创造的,应该被认为是一种模式吗? I doubt it, since OOP design patters are mainly based on inheritance to reduce code/design complexity.我对此表示怀疑,因为 OOP 设计模式主要基于 inheritance 以降低代码/设计复杂性。

Your solution needs one more step to be considered a pattern.您的解决方案需要多一步才能被视为一种模式。 Becasue, at this point your classes MyHttpAxios and MyHttpFetch have no relationship between them.因为,此时您的类MyHttpAxiosMyHttpFetch之间没有任何关系。

What is a Strategy Pattern structure for your case?您的案例的策略模式结构是什么? Based on the "oficial" structure of the design pattern, your design should look something like:根据设计模式的“官方”结构,您的设计应该类似于:

 ---------------           -----------
|  SomeClass    | <>----- | MyHttp<I> |
| client:MyHttp |         |           |
 ---------------          | +get()    | 
                           -----------
                            ^    ^
                            /    \
                           /      \
              ---------------   ---------------
             | FetchStrategy | | AxiosStrategy |
             | +get()        | | +get()        |
              ---------------   ---------------

So, SomeClass is where you will instantiate your Strategy.因此, SomeClass是您将实例化策略的地方。 MyHttp is an Interface (not planed to have instances). MyHttp是一个接口(不打算有实例)。 FetchStrategy and AxiosStrategy are your clases where you implement your code (very similar to your code). FetchStrategyAxiosStrategy是您实现代码的类(与您的代码非常相似)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM