web-dev-qa-db-ja.com

依存性注入Unity-条件付き解決

現時点では、条件付き解決は理解できません。

インターフェイスIAuthenticateがあるとしましょう:

public interface IAuthenticate{
    bool Login(string user, string pass);
}

現在、2種類の認証があります。

Twitter auth

public class TwitterAuth : IAuthenticate
{
  bool Login(string user, string pass)
{
   //connect to Twitter api
}

}

Facebook認証

public class FacebookAuth: IAuthenticate
{
  bool Login(string user, string pass)
{
   //connect to fb api
}

}

Unityの設定にタイプを登録する:

unityContainer.RegisterType<IAuthenticate, TwitterAuth>();
unityContainer.RegisterType<IAuthenticate, FacebookAuth>();

コントローラのDIを介してオブジェクトを注入します。

private readonly IAuthenticate _authenticate;

public AuthenticateController(IAuthenticate authenticate)
{
    _authenticate = authenticate;
}



// login with Twitter
public virtual ActionResult Twitter(string user, string pass)
{
    bool success =
            _authenticate.Login(user, pass);
}



// login with fb
public virtual ActionResult Facebook(string user, string pass)
{
    bool success =
            _authenticate.Login(user, pass);
}



// login with google
public virtual ActionResult Google(string user, string pass)
{
    bool success =
            _authenticate.Login(user, pass);
}

Unityは、さまざまなタイプの認証で解決する必要のあるオブジェクトをどの程度正確に認識しますか?この場合、条件付き解決をどのように行うのですか?

私の友人と話しました、そして彼がこの状況がそれが間違ったデザインであると思われるかどうかを説明しました、しかしこれは単に使用された工場パターンです。

17
amels

これを解決する簡単な方法は 戦略パターン を使用することです。設計を変更せずにログインプロバイダーを追加または削除できることに注意してください。DI構成を変更する必要があるだけです。

インターフェース

public interface IAuthenticate{
    bool Login(string user, string pass);
    bool AppliesTo(string providerName);
}

public interface IAuthenticateStrategy
{
    bool Login(string providerName, string user, string pass);
}

プロバイダーの認証

public class TwitterAuth : IAuthenticate
{
    bool Login(string user, string pass)
    {
        //connect to Twitter api
    }

    bool AppliesTo(string providerName)
    {
        // I used the type name for this example, but
        // note that you could use any string or other
        // datatype to select the correct provider.
        return this.GetType().Name.Equals(providerName);
    }
}

public class FacebookAuth: IAuthenticate
{
    bool Login(string user, string pass)
    {
        //connect to fb api
    }

    bool AppliesTo(string providerName)
    {
        return this.GetType().Name.Equals(providerName);
    }
}

戦略

public class AuthenticateStrategy: IAuthenticateStrategy
{
    private readonly IAuthenticate[] authenticateProviders;

    public AuthenticateStrategy(IAuthenticate[] authenticateProviders)
    {
        if (authenticateProviders == null)
            throw new ArgumentNullException("authenticateProviders");

        this.authenticateProviders = authenticateProviders;
    }

    public bool Login(string providerName, string user, string pass)
    {
        var provider = this.authenticateProviders
            .FirstOrDefault(x => x.AppliesTo(providerName));

        if (provider == null)
        {
            throw new Exception("Login provider not registered");
        }

        return provider.Login(user, pass);
    }
}

ユニティ登録

// Note that the strings used here for instance names have nothing 
// to do with the strings used to select the instance in the strategy pattern
unityContainer.RegisterType<IAuthenticate, TwitterAuth>("twitterAuth");
unityContainer.RegisterType<IAuthenticate, FacebookAuth>("facebookAuth");
unityContainer.RegisterType<IAuthenticateStrategy, AuthenticateStrategy>(
    new InjectionConstructor(
        new ResolvedArrayParameter<IAuthenticate>(
            new ResolvedParameter<IAuthenticate>("twitterAuth")
        ),
        new ResolvedArrayParameter<IAuthenticate>(
            new ResolvedParameter<IAuthenticate>("facebookAuth")
        )
    ));

使用法

private readonly IAuthenticateStrategy _authenticateStrategy;

public AuthenticateController(IAuthenticateStrategy authenticateStrategy)
{
    if (authenticateStrategy == null)
        throw new ArgumentNullException("authenticateStrategy");

    _authenticateStrategy = authenticateStrategy;
}



// login with Twitter
public virtual ActionResult Twitter(string user, string pass)
{
    bool success =
            _authenticateStrategy.Login("TwitterAuth", user, pass);
}



// login with fb
public virtual ActionResult Facebook(string user, string pass)
{
    bool success =
            _authenticateStrategy.Login("FacebookAuth", user, pass);
}
40
NightOwl888

Unityはあなたの助けなしではありません。 IAuthenticateタイプを登録するときに名前を指定できます。

unityContainer.RegisterType<IAuthenticate, TwitterAuth>("Twitter");
unityContainer.RegisterType<IAuthenticate, FacebookAuth>("Facebook");

IAuthenticateインスタンスをAuthenticateControllerに直接挿入する必要はなくなります。単一の条件(サービスロケータースタイル)に基づいて、必要なインスタンスを取得することもできます。

myContainer.Resolve<IAuthenticate>("Twitter");

または、これを行うファクトリを注入します(厳密なDIスタイルが必要な場合)。

6
Robert Moskal