C# 中是否有 "backwards" 观察者的概念
Is there a concept for a "backwards" observer in C#
我正在努力思考一个让我想到观察者模式的想法,但我不确定它是不是合适的地方,而且我在网上找不到任何东西(或者至少, 我问的问题不对^^).
以下示例:
// just an enum for a different tool in the ui
private ToolMode _mode;
// updates the UI according to the selected mode
private void UpdateUI(){...};
private void ChangeUIToolToMode1()
{
_mode = ToolMode.Mode1;
UpdateUI();
}
private void ChangeUIToolToMode2()
{
_mode = ToolMode.Mode2;
UpdateUI();
}
在这个例子中,我的问题是我必须在每个 ChangeUITool 方法中实现 UpadteUI() 调用。我正在寻找一种方法,将它们添加到一种调用 UpdateUI 方法的侦听器中,而不管调用哪种方法,因为应用程序可能会增长。
类似这样的伪代码:
private ToolMode _mode;
private Listener _listener;
private Init()
{
_listener= new Listener(UpdateUI);
_listener.invokingEvents.Add(ChangeUIToolToMode1);
_listener.invokingEvents.Add(ChangeUIToolToMode2);
}
如果现在调用 ChangeUITool 方法之一,侦听器应该 call/invoke UpdateUI 方法。
使用完整的 属性 定义?
// property can be private or protected as well, depending on your requirements
public ToolMode Mode
{
get { return _mode; }
set
{
if (_mode != value)
{
_mode = value;
UpdateUI();
}
}
}
如果UpdateUI
必须在包含_mode
的class之外定义,则有INotyfyPropertyChanged
接口和事件:
class Foo : INotifyPropertyChanged
{
private ToolMode _mode;
public ToolMode Mode
{
get { return _mode; }
set
{
if (_mode != value)
{
_mode = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Mode)));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
class Bar
{
private readonly Foo _foo;
public Bar()
{
_foo = new Foo();
_foo.PropertyChanged += (sender, args) => UpdateUI();
}
private void UpdateUI()
{
}
// ...
}
(这不是很好的 INPC
实现,但为了演示目的它没问题)
如果您真的想对此进行概括(并且可能这样做以便您可以响应从正在响应更改的 class 外部对 ToolMode 所做的更改),您可以在正常情况下使用事件方式。
您可以将当前的 ToolMode 封装在 class 中,然后向其中添加一个 class 事件,该事件将在 ToolMode 更改时引发。例如:
public sealed class CurrentToolMode
{
public ToolMode CurrentMode { get; private set; }
public event EventHandler ModeChanged;
public void ChangeMode(ToolMode newMode)
{
if (newMode == CurrentMode)
return;
CurrentMode = newMode;
ModeChanged?.Invoke(this, EventArgs.Empty);
}
}
然后像这样使用它:
public sealed class Test
{
public Test(CurrentToolMode mode)
{
_mode = mode;
_mode.ModeChanged += onModeChanged;
}
void onModeChanged(object sender, EventArgs e)
{
UpdateUI();
}
void UpdateUI()
{
Console.WriteLine("UpdateUI() called; mode was changed to " + _mode.CurrentMode);
}
public void SetMode1()
{
_mode.ChangeMode(ToolMode.Mode1);
}
public void SetMode2()
{
_mode.ChangeMode(ToolMode.Mode2);
}
readonly CurrentToolMode _mode;
}
在上面的示例中,CurrentToolMode
被传递给构造函数,因此可以从其他 classes 修改它。或者,您可以在构造函数中创建它,这样其他任何东西都无法更改它 - 这取决于您的使用模式。
这是一个可编译的控制台应用程序,演示了它的用法:
using System;
namespace Demo
{
class Program
{
static void Main()
{
Test test = new Test(new CurrentToolMode());
test.SetMode1();
test.SetMode2();
}
}
public sealed class Test
{
public Test(CurrentToolMode mode)
{
_mode = mode;
_mode.ModeChanged += onModeChanged;
}
void onModeChanged(object sender, EventArgs e)
{
UpdateUI();
}
void UpdateUI()
{
Console.WriteLine("UpdateUI() called; mode was changed to " + _mode.CurrentMode);
}
public void SetMode1()
{
_mode.ChangeMode(ToolMode.Mode1);
}
public void SetMode2()
{
_mode.ChangeMode(ToolMode.Mode2);
}
readonly CurrentToolMode _mode;
}
public enum ToolMode
{
None,
Mode1,
Mode2
}
public sealed class CurrentToolMode
{
public ToolMode CurrentMode { get; private set; }
public event EventHandler ModeChanged;
public void ChangeMode(ToolMode newMode)
{
if (newMode == CurrentMode)
return;
CurrentMode = newMode;
ModeChanged?.Invoke(this, EventArgs.Empty);
}
}
}
该代码的输出是:
UpdateUI() called; mode was changed to Mode1
UpdateUI() called; mode was changed to Mode2
我应该强调,如果您只打算在一个 class 中的有限数量的方法中使用这种解决方案,那么这种解决方案完全是矫枉过正,但它展示了一种响应设置更改的通用方法解耦的方式。这种方法允许任意数量的 classes 响应设置更改。
这是一个可编译的示例,显示从 class 外部更改模式以响应模式更改:
using System;
namespace Demo
{
class Program
{
static void Main()
{
CurrentToolMode mode = new CurrentToolMode();
Test test = new Test(mode);
mode.ChangeMode(ToolMode.Mode1);
mode.ChangeMode(ToolMode.Mode2);
}
}
public sealed class Test
{
public Test(CurrentToolMode mode)
{
_mode = mode;
_mode.ModeChanged += onModeChanged;
}
void onModeChanged(object sender, EventArgs e)
{
UpdateUI();
}
void UpdateUI()
{
Console.WriteLine("UpdateUI() called; mode was changed to " + _mode.CurrentMode);
}
readonly CurrentToolMode _mode;
}
public enum ToolMode
{
None,
Mode1,
Mode2
}
public sealed class CurrentToolMode
{
public ToolMode CurrentMode { get; private set; }
public event EventHandler ModeChanged;
public void ChangeMode(ToolMode newMode)
{
if (newMode == CurrentMode)
return;
CurrentMode = newMode;
ModeChanged?.Invoke(this, EventArgs.Empty);
}
}
}
我正在努力思考一个让我想到观察者模式的想法,但我不确定它是不是合适的地方,而且我在网上找不到任何东西(或者至少, 我问的问题不对^^).
以下示例:
// just an enum for a different tool in the ui
private ToolMode _mode;
// updates the UI according to the selected mode
private void UpdateUI(){...};
private void ChangeUIToolToMode1()
{
_mode = ToolMode.Mode1;
UpdateUI();
}
private void ChangeUIToolToMode2()
{
_mode = ToolMode.Mode2;
UpdateUI();
}
在这个例子中,我的问题是我必须在每个 ChangeUITool 方法中实现 UpadteUI() 调用。我正在寻找一种方法,将它们添加到一种调用 UpdateUI 方法的侦听器中,而不管调用哪种方法,因为应用程序可能会增长。
类似这样的伪代码:
private ToolMode _mode;
private Listener _listener;
private Init()
{
_listener= new Listener(UpdateUI);
_listener.invokingEvents.Add(ChangeUIToolToMode1);
_listener.invokingEvents.Add(ChangeUIToolToMode2);
}
如果现在调用 ChangeUITool 方法之一,侦听器应该 call/invoke UpdateUI 方法。
使用完整的 属性 定义?
// property can be private or protected as well, depending on your requirements
public ToolMode Mode
{
get { return _mode; }
set
{
if (_mode != value)
{
_mode = value;
UpdateUI();
}
}
}
如果UpdateUI
必须在包含_mode
的class之外定义,则有INotyfyPropertyChanged
接口和事件:
class Foo : INotifyPropertyChanged
{
private ToolMode _mode;
public ToolMode Mode
{
get { return _mode; }
set
{
if (_mode != value)
{
_mode = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Mode)));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
class Bar
{
private readonly Foo _foo;
public Bar()
{
_foo = new Foo();
_foo.PropertyChanged += (sender, args) => UpdateUI();
}
private void UpdateUI()
{
}
// ...
}
(这不是很好的 INPC
实现,但为了演示目的它没问题)
如果您真的想对此进行概括(并且可能这样做以便您可以响应从正在响应更改的 class 外部对 ToolMode 所做的更改),您可以在正常情况下使用事件方式。
您可以将当前的 ToolMode 封装在 class 中,然后向其中添加一个 class 事件,该事件将在 ToolMode 更改时引发。例如:
public sealed class CurrentToolMode
{
public ToolMode CurrentMode { get; private set; }
public event EventHandler ModeChanged;
public void ChangeMode(ToolMode newMode)
{
if (newMode == CurrentMode)
return;
CurrentMode = newMode;
ModeChanged?.Invoke(this, EventArgs.Empty);
}
}
然后像这样使用它:
public sealed class Test
{
public Test(CurrentToolMode mode)
{
_mode = mode;
_mode.ModeChanged += onModeChanged;
}
void onModeChanged(object sender, EventArgs e)
{
UpdateUI();
}
void UpdateUI()
{
Console.WriteLine("UpdateUI() called; mode was changed to " + _mode.CurrentMode);
}
public void SetMode1()
{
_mode.ChangeMode(ToolMode.Mode1);
}
public void SetMode2()
{
_mode.ChangeMode(ToolMode.Mode2);
}
readonly CurrentToolMode _mode;
}
在上面的示例中,CurrentToolMode
被传递给构造函数,因此可以从其他 classes 修改它。或者,您可以在构造函数中创建它,这样其他任何东西都无法更改它 - 这取决于您的使用模式。
这是一个可编译的控制台应用程序,演示了它的用法:
using System;
namespace Demo
{
class Program
{
static void Main()
{
Test test = new Test(new CurrentToolMode());
test.SetMode1();
test.SetMode2();
}
}
public sealed class Test
{
public Test(CurrentToolMode mode)
{
_mode = mode;
_mode.ModeChanged += onModeChanged;
}
void onModeChanged(object sender, EventArgs e)
{
UpdateUI();
}
void UpdateUI()
{
Console.WriteLine("UpdateUI() called; mode was changed to " + _mode.CurrentMode);
}
public void SetMode1()
{
_mode.ChangeMode(ToolMode.Mode1);
}
public void SetMode2()
{
_mode.ChangeMode(ToolMode.Mode2);
}
readonly CurrentToolMode _mode;
}
public enum ToolMode
{
None,
Mode1,
Mode2
}
public sealed class CurrentToolMode
{
public ToolMode CurrentMode { get; private set; }
public event EventHandler ModeChanged;
public void ChangeMode(ToolMode newMode)
{
if (newMode == CurrentMode)
return;
CurrentMode = newMode;
ModeChanged?.Invoke(this, EventArgs.Empty);
}
}
}
该代码的输出是:
UpdateUI() called; mode was changed to Mode1
UpdateUI() called; mode was changed to Mode2
我应该强调,如果您只打算在一个 class 中的有限数量的方法中使用这种解决方案,那么这种解决方案完全是矫枉过正,但它展示了一种响应设置更改的通用方法解耦的方式。这种方法允许任意数量的 classes 响应设置更改。
这是一个可编译的示例,显示从 class 外部更改模式以响应模式更改:
using System;
namespace Demo
{
class Program
{
static void Main()
{
CurrentToolMode mode = new CurrentToolMode();
Test test = new Test(mode);
mode.ChangeMode(ToolMode.Mode1);
mode.ChangeMode(ToolMode.Mode2);
}
}
public sealed class Test
{
public Test(CurrentToolMode mode)
{
_mode = mode;
_mode.ModeChanged += onModeChanged;
}
void onModeChanged(object sender, EventArgs e)
{
UpdateUI();
}
void UpdateUI()
{
Console.WriteLine("UpdateUI() called; mode was changed to " + _mode.CurrentMode);
}
readonly CurrentToolMode _mode;
}
public enum ToolMode
{
None,
Mode1,
Mode2
}
public sealed class CurrentToolMode
{
public ToolMode CurrentMode { get; private set; }
public event EventHandler ModeChanged;
public void ChangeMode(ToolMode newMode)
{
if (newMode == CurrentMode)
return;
CurrentMode = newMode;
ModeChanged?.Invoke(this, EventArgs.Empty);
}
}
}