- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在阅读了一本书和一篇在线文章中有关 SOLID 代码的内容后,我想重构一个现有的类,使其与“SOLID”兼容。
但我想我迷路了,尤其是依赖注入(inject):当我想实例化类的一个对象时,我需要“注入(inject)”所有依赖项,但依赖项本身具有依赖项..这就是我的地方开始迷路。
想法是这样的:我想创建一个类(在我的例子中,一个简单的 Amazon S3 包装器类)来执行简单的上传和获取 URL 操作。
如何正确使用接口(interface)和依赖注入(inject)?什么地方出了错?类(class)应该是什么样的?
这是我的代码:
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
}
最佳答案
根据您当前的类结构,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 )。我的建议是从应用纯 DI 开始,当手动构建对象图变得麻烦且维护繁重时,切换到 DI 库(例如 Simple Injector、Autofac 或 StructureMap)。
从依赖注入(inject)的角度来看,尽管您的代码有异味,但您所做的事情似乎很正常。以下是一些引用资料:
旁注:通常最好预先(在应用程序启动时)加载配置值,而不是在运行时读取它。在运行时读取这些值会导致以延迟方式读取这些值,从而防止应用程序快速失败,并将配置抽象的使用扩展到整个应用程序。如果可能,将这些原始配置值直接注入(inject)到需要该值的类型的构造函数中。
关于c# - 重构 SOLID 原则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36311047/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!