- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在实现模板方法模式。客户可以在此模板方法上更改几个设置;但我想阻止模板方法的实现者更改这些设置,因为在这种情况下,他们可能会破坏模板方法(基)类的不变量。如果可能的话,我希望这些东西无法编译。 (否则是时候重构策略了:))
例子:
abstract class TemplateMethod
{
// Clients of implementers of this template method change these settings before
// calling GetItems()
public SomeType RootItem { get; set; }
public bool Recursive { get; set; }
protected abstract bool ItemIsWhitelisted(SomeType item);
public IEnumerable<SomeType> GetItems()
{
var stack = new Stack<T>();
stack.Push(RootItem);
while (!stack.empty())
{
var current = stack.Pop();
if (Recursive)
{
foreach (var item in current.Children)
stack.Push(item);
}
if (!ItemIsWhitelisted(current))
yield return current;
}
}
}
class Implementer : TemplateMethod
{
protected override bool ItemIsWhitelisted(SomeType item)
{
Recursive = false; // Oops; TemplateMethod.GetItems didn't expect this
// to change inside ItemIsWhitelisted
return item.CanFrobinate();
}
}
一种方法是重构策略,生成以下内容:
interface IImplementer
{
bool ItemIswhitelisted(SomeType item);
}
sealed class NoLongerATemplateMethod
{
// Clients of implementers of this template method change these settings before
// calling GetItems()
public SomeType RootItem { get; set; }
public bool Recursive { get; set; }
public IImplementer impl { get; set; } // would be private set in real code
public IEnumerable<SomeType> GetItems()
{
var stack = new Stack<T>();
stack.Push(RootItem);
while (!stack.empty())
{
var current = stack.Pop();
if (Recursive)
{
foreach (var item in current.Children)
stack.Push(item);
}
if (!impl.ItemIsWhitelisted(current))
yield return current;
}
}
}
class Implementer : IImplementer
{
public bool ItemIsWhitelisted(SomeType item)
{
Recursive = false; // No longer compiles
return item.CanFrobinate();
}
}
我很好奇是否有一种语言功能可以在不对策略应用重构的情况下指示此约束。
最佳答案
您应该使 TemplateMethod
的设置不可变:
abstract class TemplateMethod
{
protected TemplateMethod(bool recursive)
{
Recursive = recursive;
}
public bool Recursive { get; private set; }
protected abstract bool ItemIsWhitelisted(SomeType item);
public IEnumerable<SomeType> GetItems() { /* ... */ }
}
class Implementer : TemplateMethod
{
protected override bool ItemIsWhitelisted(SomeType item)
{
Recursive = false; // Oops; Recursive is read-only
return item.CanFrobinate();
}
}
UPD。
选项#2。如果很难通过 ctor 传递设置,可以考虑注入(inject)不可变参数对象。像这样的东西(MEF 样式的示例):
public interface ISettings
{
bool Recursive { get; }
}
abstract class TemplateMethod
{
[Import]
public ISettings Settings { get; private set; }
protected abstract bool ItemIsWhitelisted(SomeType item);
public IEnumerable<SomeType> GetItems() { /* ... */ }
}
当然,这意味着 TemplateMethod
也不能更改设置。
选项#3。显式接口(interface)实现(如果 TemplateMethod
应该能够更改设置):
public interface ISettingsWriter
{
bool Recursive { set; }
}
abstract class TemplateMethod : ISettingsWriter
{
public bool Recursive { get; private set; }
bool ISettingsWriter.Recursive
{
set { Recursive = value; }
}
protected abstract bool ItemIsWhitelisted(SomeType item);
}
class Implementer : TemplateMethod
{
protected override bool ItemIsWhitelisted(SomeType item)
{
Recursive = true; // Oops; Recursive is still read-only;
return true;
}
}
当然,这意味着每个想要更改 TemplateMethod.Recursive
的人都必须将 TemplateMethod
转换为 ISettingsWriter
。
关于c# - 是否可能有派生类无法调用但类的使用者可以调用的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12813195/
我正在尝试使用包含 XPath 的选择器订阅 WebLogic JMS 消息。在 WebLogic 中,它是使用“JMS_BEA_SELECT”函数实现的。像这样的东西: session.creat
我想使用 sage 和外部 c 库。外部库已经具有用 cython 编写的 python 绑定(bind),并处理 python 的数字类和 gmp 整数之间的转换。 为了使其能够与 sage 一起使
我已经能够成功地使用 logman 来转储一些内核跟踪。但是,我希望能够以编程方式在我的应用程序中启用内核事件的实时消耗(主要是线程/进程创建/删除和文件 I/O)。完成此任务的最佳方法是什么? 最佳
我想在 FreeBSD 10.1 上编写一个 C 程序,使用 libdtrace 实现 DTrace 消费者。 我知道我需要先调用 dtrace_open() - 例如我找到了 this旧演示文稿,但
我正在尝试使用消息队列 (RabbitMQ) 在基于微服务的架构中处理请求授权。 根据这些 instructions,我已经将接收器和发送器配置为 .NET Core 中的控制台应用程序.但是,在实际
我遇到了一个场景,我必须让一个基于 Axis2 的 ws 消费者在 WebMethods 中作为 java 服务工作。我首先在 netbeans 中实现了 ws Consumer 只是为了看看它是否有
据我所知,Lambdas 用于监听事件并运行一段代码来响应这些事件。 事件必须是 AWS 服务或 HTTP 端点。 如果我有一个 RabbitMq 运行在 上的服务EC2 服务器 (不使用 SQS),
所以我正在构建一个使用 Ruby on Rails 前端和 Java 后端的 Web 应用程序。因此,基本上,当用户登录网站时,我希望在屏幕上显示该用户的所有交易数据历史记录的列表。 我需要执行此操作
我已经实现了一个 Java Servlet 过滤器,它使用 PF 提供的 Java API 从 PingFederate (PF) 服务器消耗 token 。这使得我的应用程序能够在 PF SSO 设
我有一个 WCF SOAP 使用者,它由 Visual Studio 2012 从 WSDL 实现。 WSDL 由 PeopleTools 生成。基础对象的类型为 System.ServiceMode
Oauth2 快把我逼疯了。 目前,我的 Rails 应用程序通过 Facebook 和其他 Oauth2 提供商对用户进行身份验证,这要归功于 Devise 和 OmniAuth 的美妙之处。用户无
我想获得一些关于在 Chrome 扩展和 Gmail 小工具中正确处理 Salesforce OAuth 消费者 key 和 secret 的想法。 Chrome 扩展程序本质上是用 zip 兼容格式
我正在使用 Express、Node 和 Google Drive API。我正在尝试使用 PDF 文件的 blob 响应对我的端点的 API 调用。但是当我从 Drive API 获取文件时我不想保
我是一名优秀的程序员,十分优秀!