gpt4 book ai didi

c# - 是否可能有派生类无法调用但类的使用者可以调用的方法?

转载 作者:太空狗 更新时间:2023-10-30 00:54:27 26 4
gpt4 key购买 nike

我正在实现模板方法模式。客户可以在此模板方法上更改几个设置;但我想阻止模板方法的实现者更改这些设置,因为在这种情况下,他们可能会破坏模板方法(基)类的不变量。如果可能的话,我希望这些东西无法编译。 (否则是时候重构策略了:))

例子:

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/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com