- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我选择使用组合来公开一些新行为,而不是将新对象注入(inject)到我的消费者代码中或让消费者提供自己的新行为实现。我是否做出了错误的设计决策?
我有新的要求,即我需要仅在某些情况下实现一些特殊行为。我选择定义一个新接口(interface),在一个单独负责执行行为的具体类中实现新接口(interface)。最后,在消费者引用的具体类中,我实现了新接口(interface)并将其委托(delegate)给执行该工作的类。
以下是我正在使用的假设...
这是引导我编写代码的测试...
[TestFixture]
public class UserFilesRepositoryTest
{
public interface ITestDouble : IFileManager, IAclManager { }
[Test]
public void CreateResume_AddsPermission()
{
factory.Stub(it => it.GetManager("cloudManager")).Return(testDouble);
repository.CreateResume();
testDouble.AssertWasCalled(it => it.AddPermission());
}
[SetUp]
public void Setup()
{
testDouble = MockRepository.GenerateStub<ITestDouble>();
factory = MockRepository.GenerateStub<IFileManagerFactory>();
repository = new UserFileRepository(factory);
}
private IFileManagerFactory factory;
private UserFileRepository repository;
private ITestDouble testDouble;
}
这是我设计的外壳(这只是基本轮廓,不是整个shibang)...
public class UserFileRepository
{
// this is the consumer of my code...
public void CreateResume()
{
var fileManager = factory.GetManager("cloudManager");
fileManager.AddFile();
// some would argue that I should inject a concrete implementation
// of IAclManager into the repository, I am not sure that I agree...
var permissionManager = fileManager as IAclManager;
if (permissionManager != null)
permissionManager.AddPermission();
else
throw new InvalidOperationException();
}
public UserFileRepository(IFileManagerFactory factory)
{
this.factory = factory;
}
private IFileManagerFactory factory;
}
public interface IFileManagerFactory
{
IFileManager GetManager(string managerName);
}
public class FileManagerFactory : IFileManagerFactory
{
public IFileManager GetManager(string managerName)
{
IFileManager fileManager = null;
switch (managerName) {
case "cloudManager":
fileManager = new CloudFileManager();
break;
// other managers would be created here...
}
return fileManager;
}
}
public interface IFileManager
{
void AddFile();
void DeleteFile();
}
public interface IAclManager
{
void AddPermission();
void RemovePermission();
}
/// <summary>
/// this class has "special" behavior
/// </summary>
public class CloudFileManager : IFileManager, IAclManager
{
public void AddFile() {
// implementation elided...
}
public void DeleteFile(){
// implementation elided...
}
public void AddPermission(){
// delegates to the real implementation
aclManager.AddPermission();
}
public void RemovePermission() {
// delegates to the real implementation
aclManager.RemovePermission();
}
public CloudFileManager(){
aclManager = new CloudAclManager();
}
private IAclManager aclManager;
}
public class LocalFileManager : IFileManager
{
public void AddFile() { }
public void DeleteFile() { }
}
public class DfsFileManager : IFileManager
{
public void AddFile() { }
public void DeleteFile() { }
}
/// <summary>
/// this class exists to manage permissions
/// for files in the cloud...
/// </summary>
public class CloudAclManager : IAclManager
{
public void AddPermission() {
// real implementation elided...
}
public void RemovePermission() {
// real implementation elided...
}
}
最佳答案
您添加新行为的方法只为您节省了总体方案中的初始化,因为您实现了 CloudAclManager
与 CloudFileManager
分开无论如何。我不同意一些关于如何将其与您现有设计集成的事情(这还不错)...
IFileManager
,但你没有对 IAclManager
做同样的事情。当您有一个工厂来创建各种文件管理器时,您会自动创建 CloudAclManager
IAclManager
的CloudFileManager
。那么,拥有IAclManager
有什么意义呢? ?CloudAclManager
CloudFileManager
里面每次您尝试获取其 ACL 时经理-你刚刚给了工厂对你的责任 CloudFileManager
.CloudFileManager
实现IAclManager
除了将其作为属性(property)之外。您刚刚移动了权限对 CloudFileManager
唯一的规则进入模型层而不是业务规则层。这也导致支持不必要的self 和 property 之间循环引用的潜力。CloudFileManager
委托(delegate)权限功能 CloudAclManager
,为什么要误导别人类认为 CloudFileManager
处理自己的权限集?你刚刚做了你的模型类看起来像一个门面。首先,您将类(class)命名为 CloudFileManager
,这是正确的,因为它唯一的职责是管理云文件。既然权限集也必须针对云进行管理,那么它真的适合CloudFileManager
吗?承担这些新的责任?答案是否定的。
这并不是说您不能在同一个类中使用管理文件的代码和管理权限的代码。然而,将类命名为更通用的名称(例如 CloudFileSystemManager
)会更有意义。因为它的职责不仅限于文件或权限。
不幸的是,如果您重命名您的类,则会对当前使用您的类的用户产生负面影响。那么,仍然使用组合,但不改变 CloudFileManager
怎么样? ?
我的建议是执行以下操作:
<强>1。保留您的IAclManager
并创建IFileSystemManager
public interface IFileSystemManager {
public IAclManager AclManager { get; }
public IFileManager FileManager { get; }
}
或
public interface IFileSystemManager : IAclManager, IFileManager {
}
<强>2。创建CloudFileSystemManager
public class CloudFileSystemManager : IFileSystemManager {
// implement IFileSystemManager
//
// How each manager is set is up to you (i.e IoC, DI, simple setters,
// constructor parameter, etc.).
//
// Either way you can just delegate to the actual IAclManager/IFileManager
// implementations.
}
这将允许您在使用新行为时对当前代码库/功能的影响最小,而不会影响那些使用原始代码的人。文件管理和权限管理也可以同时进行(即在尝试实际文件操作之前检查权限)。如果您需要任何其他权限集管理器或任何其他类型的管理器,它也是可扩展的。
编辑 - 包括询问者的澄清问题
IFileSystemManager : IFileManager, IAclManager
,存储库是否仍使用 FileManagerFactory 并返回 CloudFileSystemManager 的实例?不,一个FileManagerFactory
不应返回 FileSystemManager
。您的 shell 必须更新才能使用新的接口(interface)/类。也许像下面这样:
private IAclManagerFactory m_aclMgrFactory;
private IFileManagerFactory m_fileMgrFactory;
public UserFileRepository(IAclManagerFactory aclMgrFactory, IFileManagerFactory fileMgrFactory) {
this.m_aclMgrFactory = aclMgrFactory;
this.m_fileMgrFactory = fileMgrFactory;
}
public void CreateResume() {
// I understand that the determination of "cloudManager"
// is non-trivial, but that part doesn't change. For
// your example, say environment = "cloudManager"
var environment = GetEnvMgr( ... );
var fileManager = m_fileMgrFactory.GetManager(environment);
fileManager.AddFile();
// do permission stuff - see below
}
至于调用要完成的权限,您有几个选择:
// can use another way of determining that a "cloud" environment
// requires permission stuff to be done
if(environment == "cloudManager") {
var permissionManager = m_aclMgrFactory.GetManager(environment);
permissionManager.AddPermission();
}
或
// assumes that if no factory exists for the environment that
// no permission stuff needs to be done
var permissionManager = m_aclMgrFactory.GetManager(environment);
if (permissionManager != null) {
permissionManager.AddPermission();
}
关于c# - 是否应该通过组合或其他方式引入新行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4332331/
在开始之前,我想指出的是,我已经通过Google进行了一次诚实而真实的搜索,涉及范围很广,无法找到。 我需要(对于我正在开发的项目)所有Delphi(从2007年到最新发布的版本,我不再支持任何早于2
我正在使用 RPM 将 Liquibase 数据库迁移添加到我们当前的产品部署中,并正在寻找一些有关如何实现我的预期目标的建议/技巧。 最好,RPM 能够安装在全新且 Shiny 的开发人员环境以及现
我目前正在使用一本书学习 UITableViewCell。为了在滚动时重用单元格,作者要求修改原始代码以包含一个if()。检查特定重用标识符的单元格是否存在的语句。但是,在添加 if() 之后语句,X
在 C++ 中引入 protected 访问说明符背后的基本原理是什么。举个例子会有帮助。 最佳答案 对于这类问题,我推荐 Bjarne Stroustrup 的The Design And Evol
我正在尝试使用模板参数中给定的维度和类型创建一个可重用的矩阵类。结构本身就是: template struct Matrix { T elements[N* M]; }; 当我尝试实现矩阵乘
我有一个简单的查询: $query1="SELECT * FROM wp_users WHERE now() < (last_login + INTERVAL 6 month)"; $resu
在 Ioke doc 中,ISpec 测试包含在文档中,参见 ioke.org/dok/index.html 这如何用 Ruby 的 RSpec 和 RDoc(或 SDoc)来完成?我找不到任何命令行
在客户端/服务器通信中,我看到来自客户端的 TCP ZeroWindow。 在这种情况之后预期的场景是什么(设置和发送什么标志)? 以下是我可能得到的日志。在这种情况下,服务器发送 RST 数据包来终
来自wikipedia关于 Lambda 函数和表达式的文章: users will often wish to define predicate functions near the place w
我有一个由父 POM 和几个子模块组成的 Maven 项目。它在 Intellij 中编译和运行良好(我假设它使用 javac 而不是 Maven)。 当我运行 maven clean install
所以我刚开始使用 d3.js,但我一直收到 JavaScript 错误,我不知道为什么。我刚刚用 svg 创建了三个圆圈,想用 d3 选择它们。这是我的代码:
Objective C 引入了一种称为 ARC 的技术,以将开发人员从内存管理的负担中解放出来。听起来不错,如果g++也有这个功能,我想C++开发者会很高兴的。 ARC allows you to p
在 package.json 添加 "font-awesome": "^4.7.0" 执行 npm install 在 main.js 引入
为什么 WSDL 引入 wsdl:message?和消息部分? 与在操作参数(输入、输出、故障)中直接使用 XSD 相比,他们可以带来什么优势? 它们(带有 wsdl 消息部分的 wsdl 消息)如何
I already read doc here : https://github.com/laravel/framework/pull/25997 我想知道的是使用 withCount()我们只是加载
我已经为此苦苦挣扎了一段时间,但不太明白发生了什么。我有一个包含 Sides(通常是 2 个)的 Card 实体 - 并且 Cards 和 Sides 都有一个 Stage。我正在使用 EF Code
下面的 swiftUI 代码在 iOS13 上运行良好,但是在使用 iOS14 进行测试时,我在尝试显示模式表时遇到了由强制解包选项引起的 fatal error 。据我所知,工作表不应该尝试为 se
出于个人原因,我需要记忆一下 jsp 上的一些事情 :) 我有一个简单的登录页面: Login First name:
据我了解,PYTHONCASEOK 选项允许通过不区分大小写的匹配来导入模块。但是,由于 python 中的几乎所有内容都区分大小写,为什么它必须启用此选项以实现更惰性的写入。 还有什么介绍的理由吗?
全新的早午餐(和 bower )。我通过 bower 安装了 Bootstrap,我有以下早午餐配置文件: exports.config = # See http://brunch.io/#doc
我是一名优秀的程序员,十分优秀!