gpt4 book ai didi

design-patterns - 使用多个提供程序的客户端应用程序应使用哪种设计/模式?

转载 作者:行者123 更新时间:2023-12-02 03:22:17 26 4
gpt4 key购买 nike

这是与设计有关的问题。

可以说我们有一个称为ClientAPI的 public API,其中包含一些Web方法,例如CreateAccount,GetAccount。根据客户的不同,我们使用许多不同的提供商来满足这些要求。

假设我们有ProviderA和ProviderB以及ProviderC。

ProviderA具有仅需要(名字,姓氏)并使用ProviderA创建帐户的CreateAccount的方法签名/实现。

ProviderB具有需要(名字,姓氏,电子邮件,DOB)的CreateAccount的方法签名/实现,并使用ProviderB创建帐户。

ProviderC具有需要(昵称,公司密钥,电子邮件)的CreateAccount方法签名/实现,并使用ProviderC创建帐户。

客户无需了解或关心他们是哪个提供商。调用客户端API方法CreateAccount时,客户端api将确定需要调用哪些提供程序并调用该Providers方法。

我在这里有两个问题。

1)对此模型实施的最佳设计/模式是什么?另外请记住,提供者的数量将会增加–我们将增加更多的提供者。

2)关于传递参数–当前,ClientAPI CreateAccount方法签名是一大行变量,如果新提供程序需要新值,则该方法签名将添加另一个变量,这显然会破坏旧的实现方式等。将方法签名中的参数的数组/列表/字典传递给下面的提供程序的良好实践,还是有更好的方法?

最佳答案

这确实是一个有趣的问题。在我从事的不同项目中,我遇到了一些类似的问题。阅读您的问题后,我注意到您面临两个不同的挑战:

  • 通过ClientAPI正确选择提供者
  • 每个提供程序所需的变量数量和参数类型。

  • 在设计服务或新功能时,我想通过尽量减少为支持新功能而需要进行的更改数量来进行设计。在您的情况下,将添加新的身份验证提供程序。我现在至少想到了三种实现方法。我认为,没有完美的解决方案。您将不得不基于权衡选择其中之一。下面,我尝试提出一些解决上面列出的两个痛点的方法,以及它们的优缺点。

    类型松弛

    无论我们做什么,无论我们使用多态性抽象复杂性有多好,总会有一个不同的类型或组件通过要求不同的信息集来使其与同类区别。根据要在设计中投入多少精力以保持其强类型化以及多态抽象的不同程度,添加新功能时需要进行更多更改。下面是一个不对用户提供的所有信息强制执行类型的实现示例。
    public class UserData {
    private AuthType type;
    private String firstname;
    private String lastname;
    private Map<String, String> metadata;
    }

    public enum AuthType {
    FACEBOOK, GPLUS, TWITTER;
    }

    public interface AuthProvider {
    void createAccount(UserData userData);
    void login(UserCredentials userCredentials);
    }

    public class AuthProviderFactory {
    public AuthProvider get(AuthType type) {
    switch(type) {
    case FACEBOOK:
    return new FacebookAuthProvider();
    case GPLUS:
    return new GPlusAuthProvider();
    case TWITTER:
    return new TwitterAuthProvider();
    default:
    throw new IllegalArgumentException(String.format('Invalid authentication type %s', type));
    }
    }
    }

    // example of usage
    UserData userData = new UserData();
    userData.setAuthType(AuthType.FACEBOOK);
    userData.setFirstname('John');
    userData.setLastname('Doe');
    userData.putExtra('dateOfBirth', LocalDate.of(1997, 1, 1));
    userData.putExtra('email', Email.fromString('john.doe@gmail.com'));

    AuthProvider authProvider = new AuthProviderFactory().get(userData.getType());
    authProvider.createAccount(userData);

    好处
  • 只需将新条目添加到AuthTypeAuthProviderFactory即可支持新的提供程序。
  • 每个AuthProvider确切知道执行公开操作所需的内容(createAccount()等)。逻辑和复杂性得到了很好的封装。

  • 缺点
  • 不会严格键入UserData中的几个参数。一些需要附加参数的AuthProvider将不得不查找它们,即metadata.get('email')


  • 键入 UserData
    我假设负责 AuthProviderFactory调用的组件已经对所需的提供程序类型有所了解,因为它必须用成功 UserData调用所需的所有信息来填充 createAccount()。那么,如何让该组件创建正确的 UserData类型呢?
    public class UserData {
    private String firstname;
    private String lastname;
    }

    public class FacebookUserData extends UserData {
    private LocalDate dateOfBirth;
    private Email email;
    }

    public class GplusUserData extends UserData {
    private Email email;
    }

    public class TwitterUserData extends UserData {
    private Nickname nickname;
    }

    public interface AuthProvider {
    void createAccount(UserData userData);
    void login(UserCredentials userCredentials);
    }

    public class AuthProviderFactory {
    public AuthProvider get(UserData userData) {
    if (userData instanceof FacebookUserData) {
    return new FacebookAuthProvider();
    } else if (userData instanceof GplusUserData) {
    return new GPlusAuthProvider();
    } else if (userData instanceof TwitterUserData) {
    return new TwitterAuthProvider();
    }
    throw new IllegalArgumentException(String.format('Invalid authentication type %s', userData.getClass()));
    }
    }

    // example of usage
    FacebookUserData userData = new FacebookUserData();
    userData.setFirstname('John');
    userData.setLastname('Doe');
    userData.setDateOfBirth(LocalDate.of(1997, 1, 1));
    userData.setEmail(Email.fromString('john.doe@gmail.com'));

    AuthProvider authProvider = new AuthProviderFactory().get(userData);
    authProvider.createAccount(userData);

    好处
  • 包含强类型属性的UserData的特殊形式。
  • 只需创建新的UserData类型并添加新的条目AuthProviderFactory即可支持新的提供程序。
  • 每个AuthProvider确切知道执行公开操作所需的内容(createAccount()等)。逻辑和复杂性得到了很好的封装。

  • 缺点
  • AuthProviderFactory使用instanceof选择适当的AuthProvider
  • UserData子类型爆炸,并可能重复代码。


  • 再次输入 UserData
    我们可以尝试通过将枚举 AuthType重新引入我们以前的设计中,并使我们的 UserData子类更加通用,来消除代码重复。
    public interface UserData {
    AuthType getType();
    }

    public enum AuthType {
    FACEBOOK, GPLUS, TWITTER;
    }

    public class BasicUserData implements UserData {
    private AuthType type:
    private String firstname;
    private String lastname;

    public AuthType getType() { return type; }
    }

    public class FullUserData extends BasicUserData {
    private LocalDate dateOfBirth;
    private Email email;
    }

    public class EmailUserData extends BasicUserData {
    private Email email;
    }

    public class NicknameUserData extends BasicUserData {
    private Nickname nickname;
    }

    public interface AuthProvider {
    void createAccount(UserData userData);
    void login(UserCredentials userCredentials);
    }

    public class AuthProviderFactory {
    public AuthProvider get(AuthType type) {
    switch(type) {
    case FACEBOOK:
    return new FacebookAuthProvider();
    case GPLUS:
    return new GPlusAuthProvider();
    case TWITTER:
    return new TwitterAuthProvider();
    default:
    throw new IllegalArgumentException(String.format('Invalid authentication type %s', type));
    }
    }
    }

    // example of usage
    FullUserData userData = new FullUserData();
    userData.setAuthType(AuthType.FACEBOOK);
    userData.setFirstname('John');
    userData.setLastname('Doe');
    userData.setDateOfBirth(LocalDate.of(1997, 1, 1));
    userData.setEmail(Email.fromString('john.doe@gmail.com'));

    AuthProvider authProvider = new AuthProviderFactory().get(userData.getType());
    authProvider.createAccount(userData);

    好处
  • 包含强类型属性的UserData的特殊形式。
  • 每个AuthProvider确切知道执行公开操作所需的内容(createAccount()等)。逻辑和复杂性得到了很好的封装。

  • 缺点
  • 除了向AuthProviderFactory添加新条目并为UserData创建新的子类型之外,新的提供程序还需要在枚举AuthType中添加一个新条目。
  • 我们仍然有UserData子类型的爆炸式增长,但是现在这些子类型的可重用性得到了提高。

  • 概要

    我很确定还有其他解决方案。如上所述,也没有完美的解决方案。您可能必须根据他们的权衡和想要实现的目标选择一个。

    我今天的灵感还不是很好,所以如果我有其他想法,我会继续更新。

    关于design-patterns - 使用多个提供程序的客户端应用程序应使用哪种设计/模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32474587/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com