2016-03-30 24 views
2

書籍やオンラインの記事でSOLIDコードを読んだ後、既存のクラスをリファクタリングして、SOLID互換にしたいと考えました。SOLIDの原則のリファクタリング

私はクラスのオブジェクトをインスタンス化したいとき、すべての依存関係を注入する必要がありましたが、依存関係自体に依存関係があります。私は迷子になり始めた。

アイデアは次のようなものです:簡単なアップロード& URLアクションを取得するクラス(私の場合、単純なAmazon S3ラッパークラス)を作成したいと思います。

インターフェイスと依存関係注入を正しく使用するにはどうすればよいですか?何が悪かったのか? クラスはどのように見えるでしょうか?ここ

が私のコードです:あなたの現在のクラス構造で

public interface IConfigurationProvider 
{ 
    string GetConfigurationValue(String configurationKey); 
} 

public interface ILogger 
{ 
    void WriteLog(String message); 
} 

public interface IAWSClientProvider 
{ 
    AmazonS3Client GetAmazonS3Client(); 
} 

public interface IAWSBucketManager 
{ 
    string GetDefaultBucketName(); 
} 

public class AWSBucketManager : IAWSBucketManager 
{ 
    ILogger logger; 
    IConfigurationProvider configurationProvider; 

    public AWSBucketManager(ILogger Logger, IConfigurationProvider ConfigurationProvider) 
    { 
     logger = Logger; 
     configurationProvider = ConfigurationProvider; 
    } 

    public string GetDefaultBucketName() 
    { 
     string bucketName = string.Empty; 

     try 
     { 
      bucketName = configurationProvider.GetConfigurationValue("Amazon_S3_ExportAds_BucketName"); 
     } 
     catch (Exception ex) 
     { 
      logger.WriteLog(String.Format("getBucketName : Unable to get bucket name from configuration.\r\n{0}", ex)); 
     } 

     return bucketName; 
    } 
} 

public class AWSClientProvider : IAWSClientProvider 
{ 
    IConfigurationProvider configurationProvider; 
    IAWSBucketManager awsBucketManager; 
    ILogger logger; 

    private string awsS3BucketName; 
    private Dictionary<string, RegionEndpoint> regionEndpoints; 

    public AWSClientProvider(IConfigurationProvider ConfigurationProvider, IAWSBucketManager BucketManager, ILogger Logger) 
    { 
     logger = Logger; 
     configurationProvider = ConfigurationProvider; 
     awsBucketManager = BucketManager; 
    } 

    private RegionEndpoint getAWSRegion() 
    { 
     RegionEndpoint regionEndpoint = null; 
     // Init endpoints dictionary 
     try 
     { 
      IEnumerable<RegionEndpoint> regions = RegionEndpoint.EnumerableAllRegions; 
      regionEndpoints = regions.ToDictionary(r => r.SystemName, r => r); 
     } 
     catch (Exception Ex) 
     { 
      logger.WriteLog(String.Format("getAWSRegion() - Failed to get region list from AWS.\r\n{0}", Ex)); 
      throw; 
     } 
     // Get configuration value 
     try 
     { 
      string Config = configurationProvider.GetConfigurationValue("Amazon_S3_Region"); 
      if (String.IsNullOrEmpty(Config)) 
      { 
       throw new Exception("getAWSRegion() : Amazon_S3_Region must not be null or empty string."); 
      } 

      regionEndpoint = regionEndpoints[Config]; 
     } 
     catch (Exception Ex) 
     { 
      logger.WriteLog(String.Format("getAWSRegion() : Unable to get region settings from configuration.\r\n{0}", Ex)); 
      throw Ex; 
     } 

     return regionEndpoint; 
    } 

    private AWSCredentials getAWSCredentials() 
    { 
     string accessKey, secretKey; 
     BasicAWSCredentials awsCredentials; 

     try 
     { 
      accessKey = configurationProvider.GetConfigurationValue("Amazon_S3_AccessKey"); 
      secretKey = configurationProvider.GetConfigurationValue("Amazon_S3_SecretKey"); 
     } 
     catch (Exception Ex) 
     { 
      logger.WriteLog(String.Format("getAWSCredentials() - Unable to get access key and secrey key values from configuration.\r\n", Ex.Message)); 
      throw; 
     } 

     try 
     { 
      awsCredentials = new BasicAWSCredentials(accessKey, secretKey); 
     } 
     catch (Exception Ex) 
     { 
      logger.WriteLog(String.Format("getAWSCredentials() - Unable to create basic AWS credentials object.\r\n{0}", Ex.Message)); 
      awsCredentials = null; 
      throw; 
     } 

     return awsCredentials; 
    } 

    public AmazonS3Client GetAmazonS3Client() 
    { 
     AmazonS3Client client = null; 
     RegionEndpoint region = getAWSRegion(); 
     AWSCredentials credentials = getAWSCredentials(); 
     awsS3BucketName = awsBucketManager.GetDefaultBucketName(); 

     if (credentials != null) 
     { 
      client = new AmazonS3Client(credentials, region); 
     } 
     return client; 
    } 
} 

public class AWSS3Actions 
{ 
    IConfigurationProvider configurationProvider;  // decoupling getting configuration 
    ILogger logger;          // decoupling logger 
    IAWSClientProvider awsClientProvider; 

    private const int defaultExpirationDays = 14; 

    public AWSS3Actions(IConfigurationProvider ConfigurationProvider, ILogger Logger, IAWSClientProvider ClientProvider) 
    { 
     configurationProvider = ConfigurationProvider; 
     logger = Logger; 
     awsClientProvider = ClientProvider; 
    } 

    #region Private Mmethods 

    private string getFileUrl(string fileName, int expirationDaysPeriod, string awsS3BucketName) 
    { 
     GetPreSignedUrlRequest request = new GetPreSignedUrlRequest(); 
     string URL = ""; 

     DateTime dtBase = new DateTime(); 
     dtBase = DateTime.Now; 
     dtBase = dtBase.AddDays(expirationDaysPeriod); 

     request.BucketName = awsS3BucketName; 
     request.Key = fileName; 
     request.Expires = dtBase; 

     try 
     { 
      URL = awsClientProvider.GetAmazonS3Client().GetPreSignedURL(request); 
     } 
     catch (AmazonS3Exception ex) 
     { 
      // log 
      logger.WriteLog(String.Format("getFileUrl() : Could not get presigned URL for the provided request.\r\n{0}", ex)); 
      throw ex; 
     } 

     return URL; 
    } 

    private int getDefaultURLExpiration() 
    { 
     int expirationDays = 0; 
     try 
     { 
      // set the time span in days 
      int.TryParse(configurationProvider.GetConfigurationValue("getDefaultURLExpiration() : Amazon_S3_ExportAds_ExpirationDaysOfURL"), out expirationDays);  // get from configuration util 
     } 
     catch 
     { 
      // in case of exception, set the min 14 days time space exiration 
      expirationDays = defaultExpirationDays; 
     } 
     return expirationDays; 
    } 

    private void validateUpload(string fileName, Stream fileStream) 
    { 
     if (fileName == null || fileName.Equals(string.Empty) || fileStream.Length < 1) 
     { 
      throw new Exception("fileName : File name must not be an empty string."); 
     } 
     if (fileStream == null) 
     { 
      throw new Exception("fileStream : Input memory stream (file stream) must not be null."); 
     } 
    } 

    #endregion 

    #region Public methods 

    public bool IsFileExists(string fileName, string awsS3BucketName) 
    { 
     bool fileExists = false; 
     try 
     { 
      S3FileInfo fileInfo = new S3FileInfo(awsClientProvider.GetAmazonS3Client(), awsS3BucketName, fileName); 
      fileExists = fileInfo.Exists; 
     } 
     catch (AmazonS3Exception Ex) 
     { 
      // log 
      logger.WriteLog(String.Format("isFileExists() : Could not determine if file (key) exists in S3 Bucket.\r\n", Ex.Message)); 
      throw; 
     } 
     return fileExists; 
    } 

    public bool UploadObject(string fileName, Stream fileStream, string awsS3BucketName) 
    { 
     bool uploadResult = true; 
     // Validate input parameters 
     validateUpload(fileName, fileStream); 

     if (awsClientProvider.GetAmazonS3Client() != null) 
     { 
      try 
      { 
       PutObjectRequest request = new PutObjectRequest 
       { 
        BucketName = awsS3BucketName, 
        Key = fileName, 
        InputStream = fileStream 
       }; 

       PutObjectResponse response = awsClientProvider.GetAmazonS3Client().PutObject(request); 
       if (response != null) 
       { 
        if (response.HttpStatusCode != System.Net.HttpStatusCode.OK) 
        { 
         var meta = response.ResponseMetadata.Metadata.Keys. 
          Select(k => k.ToString() + " : " + response.ResponseMetadata.Metadata[k]). 
          ToList().Aggregate((current, next) => current + "\r\n" + next); 

         // log error 
         logger.WriteLog(String.Format("Status Code: {0}\r\nETag : {1}\r\nResponse metadata : {1}", 
          (int)response.HttpStatusCode, response.ETag, meta)); 

         // set the return value 
         uploadResult = false; 
        } 
       } 
      } 
      catch (AmazonS3Exception ex) 
      { 
       uploadResult = false; 

       if (ex.ErrorCode != null && (ex.ErrorCode.Equals("InvalidAccessKeyId") || ex.ErrorCode.Equals("InvalidSecurity"))) 
       { 
        // LOG 
        logger.WriteLog(String.Format("UploadObject() : invalied credentials")); 
        throw ex; 
       } 
       else 
       { 
        // LOG 
        logger.WriteLog(String.Format("UploadObject() : Error occurred. Message:'{0}' when writing an object", ex.Message)); 
        throw ex; 
       } 
      } 
     } 
     else 
     { 
      throw new Exception("UploadObject() : Could not start object upload because Amazon client is null."); 
     } 

     return uploadResult; 
    } 

    public bool UploadObject(string subFolderInBucket, string FileName, Stream fileStream, string awsS3BucketName) 
    { 
     return UploadObject(subFolderInBucket + @"/" + FileName, fileStream, awsS3BucketName); 
    } 

    public string GetURL(string fileName, string bucket) 
    { 
     string url = string.Empty; 
     try 
     { 
      if (IsFileExists(fileName, bucket)) 
      { 
       url = getFileUrl(fileName, getDefaultURLExpiration(), bucket); 
      } 
     } 
     catch (Exception Ex) 
     { 
      // log 
      logger.WriteLog(String.Format("getURL : Failed in isFileExists() method. \r\n{0}", Ex.Message)); 
     } 
     return url; 
    } 

    #endregion 
} 
+1

あなたは新しいものをすべて自分の前で立ち上げる(貧乏人のDI)か、DIコンテナを使って管理します。あなたがそれらを探す場合に使用できる多くの既存の容器があります。 – Nkosi

+0

Castle Windsor Inversion of Controlコンテナをチェックしてください。オブジェクトをインスタンス化して注入するために必要なすべてを行います。 –

+0

あなたの質問はかなり漠然としており、特定の質問なしにコードの巨大な広報を投稿することは役に立たない。具体的に何を求めているのですか?私は特にコードに "間違った"ものは何も見られません。 –

答えて

3

Composition Rootは次のようになります。

var logger = new FileLogger("c:\\temp\\log.txt"); 
var configurationProvider = new ConfigurationProvider(); 

var actions = new AWSS3Actions(
    configurationProvider, 
    logger, 
    new AWSClientProvider(
     configurationProvider, 
     new AWSBucketManagerlogger(
      logger, 
      configurationProvider), 
     logger)); 

上記の例では、手有線オブジェクトグラフ(別名Pure DI)を示し、 。手作業でオブジェクトグラフを作成するのが面倒でメンテナンスが重くなると、Pure DIを適用してDIライブラリ(Simple Injector、Autofac、StructureMapなど)に切り替えることから始めることをお勧めします。

依存性注入の観点から、あなたのコードのにおいはしていますが、あなたは何をしているのでしょうか。一般的には、(起動アプリケーションで)アップフロントの設定値をロードすると良いでしょう、ではなく:

サイドノート:ここを見て、いくつかの参照です実行時にそれを読む。これらの値を実行時に読み取ると、これらの値が遅延して読み込まれ、アプリケーションの高速化が妨げられ、アプリケーション全体で構成抽象化の使用が広がります。可能であれば、それらのプリミティブ構成値を、その値を必要とするタイプのコンストラクターに直接注入します。

関連する問題