Design Pattern - Observer(C#)

本文深入讲解了观察者模式的设计理念,通过C#代码实例演示了如何实现对象间的一对多依赖关系,当一个对象状态改变时,所有依赖的对象都会收到通知并自动更新。包括抽象主题类、具体主题类、抽象观察者类和具体观察者类的定义及其实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.youkuaiyun.com/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

Definition

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Participants

    The classes and/or objects participating in this pattern are:

  • Subject  (Stock) 
    • Knows its observers. Any number of Observer objects may observe a subject
    •   
    • Provides an interface for attaching and detaching Observer objects.
    •  
  •  
  • ConcreteSubject  (IBM) 
    • Stores state of interest to ConcreteObserver
    •   
    • Sends a notification to its observers when its state changes
    •  
  •  
  • Observer  (IInvestor) 
    • Defines an updating interface for objects that should be notified of changes in a subject.
    •  
  •  
  • ConcreteObserver  (Investor) 
    • Maintains a reference to a ConcreteSubject object
    •   
    • Stores state that should stay consistent with the subject's
    •   
    • Implements the Observer updating interface to keep its state consistent with the subject's
    •  

Sample Code in C#


This structural code demonstrates the Observer pattern in which registered objects are notified of and updated with a state change.

// --------------------------------------------------------------------------------------------------------------------// <copyright company="Chimomo's Company" file="Program.cs">// Respect the work.// </copyright>// <summary>// Structural Observer Design Pattern.// </summary>// --------------------------------------------------------------------------------------------------------------------namespace CSharpLearning{    using System;    using System.Collections.Generic;    /// <summary>    /// Startup class for Structural Observer Design Pattern.    /// </summary>    internal static class Program    {        #region Methods        /// <summary>        /// Entry point into console application.        /// </summary>        private static void Main()        {            // Configure Observer pattern            var s = new ConcreteSubject();            s.Attach(new ConcreteObserver(s, "X"));            s.Attach(new ConcreteObserver(s, "Y"));            s.Attach(new ConcreteObserver(s, "Z"));            // Change subject and notify observers            s.SubjectState = "ABC";            s.Notify();        }        #endregion    }    /// <summary>    /// The 'Subject' abstract class    /// </summary>    internal abstract class Subject    {        #region Fields        /// <summary>        /// The observers.        /// </summary>        private List<Observer> observers = new List<Observer>();        #endregion        #region Public Methods and Operators        /// <summary>        /// The attach.        /// </summary>        /// <param name="observer">        /// The observer.        /// </param>        public void Attach(Observer observer)        {            this.observers.Add(observer);        }        /// <summary>        /// The detach.        /// </summary>        /// <param name="observer">        /// The observer.        /// </param>        public void Detach(Observer observer)        {            this.observers.Remove(observer);        }        /// <summary>        /// The notify.        /// </summary>        public void Notify()        {            foreach (Observer o in this.observers)            {                o.Update();            }        }        #endregion    }    /// <summary>    /// The 'ConcreteSubject' class    /// </summary>    internal class ConcreteSubject : Subject    {        // Gets or sets subject state        #region Public Properties        /// <summary>        /// Gets or sets the subject state.        /// </summary>        public string SubjectState { get; set; }        #endregion    }    /// <summary>    /// The 'Observer' abstract class    /// </summary>    internal abstract class Observer    {        #region Public Methods and Operators        /// <summary>        /// The update.        /// </summary>        public abstract void Update();        #endregion    }    /// <summary>    /// The 'ConcreteObserver' class    /// </summary>    internal class ConcreteObserver : Observer    {        #region Fields        /// <summary>        /// The name.        /// </summary>        private string name;        /// <summary>        /// The observer state.        /// </summary>        private string observerState;        /// <summary>        /// The subject.        /// </summary>        private ConcreteSubject subject;        #endregion        // Constructor        #region Constructors and Destructors        /// <summary>        /// Initializes a new instance of the <see cref="ConcreteObserver"/> class.        /// </summary>        /// <param name="subject">        /// The subject.        /// </param>        /// <param name="name">        /// The name.        /// </param>        public ConcreteObserver(ConcreteSubject subject, string name)        {            this.subject = subject;            this.name = name;        }        #endregion        #region Public Properties        /// <summary>        /// Gets or sets the subject.        /// </summary>        public ConcreteSubject Subject        {            get            {                return this.subject;            }            set            {                this.subject = value;            }        }        #endregion        #region Public Methods and Operators        /// <summary>        /// The update.        /// </summary>        public override void Update()        {            this.observerState = this.subject.SubjectState;            Console.WriteLine("Observer {0}'s new state is {1}", this.name, this.observerState);        }        #endregion    }}// Output:/*Observer X's new state is ABCObserver Y's new state is ABCObserver Z's new state is ABC*/

 


This real-world code demonstrates the Observer pattern in which registered investors are notified every time a stock changes value.

// --------------------------------------------------------------------------------------------------------------------// <copyright company="Chimomo's Company" file="Program.cs">//  Respect the work.// </copyright>// <summary>//  Real-World Observer Design Pattern.// </summary>// --------------------------------------------------------------------------------------------------------------------namespace CSharpLearning{    using System;    using System.Collections.Generic;    /// <summary>    /// The 'Observer' interface    /// </summary>    internal interface IInvestor    {        #region Public Methods and Operators        /// <summary>        /// The update.        /// </summary>        /// <param name="stock">        /// The stock.        /// </param>        void Update(Stock stock);        #endregion    }    /// <summary>    /// Startup class for Real-World Observer Design Pattern.    /// </summary>    internal static class Program    {        #region Methods        /// <summary>        /// Entry point into console application.        /// </summary>        private static void Main()        {            // Create IBM stock and attach investors            var ibm = new IBM("IBM", 120.00);            ibm.Attach(new Investor("Sorros"));            ibm.Attach(new Investor("Berkshire"));            // Fluctuating prices will notify investors            ibm.Price = 120.10;            ibm.Price = 121.00;            ibm.Price = 120.50;            ibm.Price = 120.75;        }        #endregion    }    /// <summary>    /// The 'Subject' abstract class    /// </summary>    internal abstract class Stock    {        #region Fields        /// <summary>        /// The investors.        /// </summary>        private List<IInvestor> investors = new List<IInvestor>();        /// <summary>        /// The price.        /// </summary>        private double price;        #endregion        // Constructor        #region Constructors and Destructors        /// <summary>        /// Initializes a new instance of the <see cref="Stock"/> class.        /// </summary>        /// <param name="symbol">        /// The symbol.        /// </param>        /// <param name="price">        /// The price.        /// </param>        protected Stock(string symbol, double price)        {            this.Symbol = symbol;            this.price = price;        }        #endregion        #region Public Properties        /// <summary>        /// Gets or sets the price.        /// </summary>        public double Price        {            get            {                return this.price;            }            set            {                if (this.price != value)                {                    this.price = value;                    this.Notify();                }            }        }        /// <summary>        /// Gets the symbol.        /// </summary>        public string Symbol { get; private set; }        #endregion        #region Public Methods and Operators        /// <summary>        /// The attach.        /// </summary>        /// <param name="investor">        /// The investor.        /// </param>        public void Attach(IInvestor investor)        {            this.investors.Add(investor);        }        /// <summary>        /// The detach.        /// </summary>        /// <param name="investor">        /// The investor.        /// </param>        public void Detach(IInvestor investor)        {            this.investors.Remove(investor);        }        /// <summary>        /// The notify.        /// </summary>        public void Notify()        {            foreach (IInvestor investor in this.investors)            {                investor.Update(this);            }            Console.WriteLine(string.Empty);        }        #endregion        // Gets or sets the price    }    /// <summary>    /// The 'ConcreteSubject' class    /// </summary>    internal class IBM : Stock    {        // Constructor        #region Constructors and Destructors        /// <summary>        /// Initializes a new instance of the <see cref="IBM"/> class.        /// </summary>        /// <param name="symbol">        /// The symbol.        /// </param>        /// <param name="price">        /// The price.        /// </param>        public IBM(string symbol, double price)            : base(symbol, price)        {        }        #endregion    }    /// <summary>    /// The 'ConcreteObserver' class    /// </summary>    internal class Investor : IInvestor    {        #region Fields        /// <summary>        /// The name.        /// </summary>        private string name;        #endregion        // Constructor        #region Constructors and Destructors        /// <summary>        /// Initializes a new instance of the <see cref="Investor"/> class.        /// </summary>        /// <param name="name">        /// The name.        /// </param>        public Investor(string name)        {            this.name = name;        }        #endregion        // Gets or sets the stock        #region Public Properties        /// <summary>        /// Gets or sets the stock.        /// </summary>        public Stock Stock { get; set; }        #endregion        #region Public Methods and Operators        /// <summary>        /// The update.        /// </summary>        /// <param name="stock">        /// The stock.        /// </param>        public void Update(Stock stock)        {            Console.WriteLine("Notified {0} of {1}'s " + "change to {2:C}", this.name, stock.Symbol, stock.Price);        }        #endregion    }}// Output:/*Notified Sorros of IBM's change to $120.10Notified Berkshire of IBM's change to $120.10Notified Sorros of IBM's change to $121.00Notified Berkshire of IBM's change to $121.00Notified Sorros of IBM's change to $120.50Notified Berkshire of IBM's change to $120.50Notified Sorros of IBM's change to $120.75Notified Berkshire of IBM's change to $120.75*/

 

           

给我老师的人工智能教程打call!http://blog.youkuaiyun.com/jiangjunshow
这里写图片描述
资源下载链接为: https://pan.quark.cn/s/d9ef5828b597 在本文中,我们将探讨如何通过 Vue.js 实现一个带有动画效果的“回到顶部”功能。Vue.js 是一款用于构建用户界面的流行 JavaScript 框架,其组件化和响应式设计让实现这种交互功能变得十分便捷。 首先,我们来分析 HTML 代码。在这个示例中,存在一个 ID 为 back-to-top 的 div 元素,其中包含两个 span 标签,分别显示“回到”和“顶部”文字。该 div 元素绑定了 Vue.js 的 @click 事件处理器 backToTop,用于处理点击事件,同时还绑定了 v-show 指令来控制按钮的显示与隐藏。v-cloak 指令的作用是在 Vue 实例渲染完成之前隐藏该元素,避免出现闪烁现象。 CSS 部分(backTop.css)主要负责样式设计。它首先清除了一些默认的边距和填充,对 html 和 body 进行了全屏布局,并设置了相对定位。.back-to-top 类则定义了“回到顶部”按钮的样式,包括其位置、圆角、阴影、填充以及悬停时背景颜色的变化。此外,与 v-cloak 相关的 CSS 确保在 Vue 实例加载过程中隐藏该元素。每个 .page 类代表一个页面,每个页面的高度设置为 400px,用于模拟多页面的滚动效果。 接下来是 JavaScript 部分(backTop.js)。在这里,我们创建了一个 Vue 实例。实例的 el 属性指定 Vue 将挂载到的 DOM 元素(#back-to-top)。data 对象中包含三个属性:backTopShow 用于控制按钮的显示状态;backTopAllow 用于防止用户快速连续点击;backSeconds 定义了回到顶部所需的时间;showPx 则规定了滚动多少像素后显示“回到顶部”按钮。 在 V
<think>我们正在讨论C# WinForms应用程序中适合在运行时使用的设计模式。用户可能希望了解那些能够动态改变应用行为或结构的模式。 根据WinForms的事件驱动特性,以及需要动态响应和灵活性,以下模式特别适用: 1. 观察者模式(Observer Pattern):WinForms本身大量使用事件(event),这就是观察者模式的实现。我们可以通过事件订阅和取消订阅在运行时动态改变行为。 2. 策略模式(Strategy Pattern):用于在运行时选择算法或行为。例如,我们可以定义一系列算法,封装它们,并使它们可以互换。 3. 状态模式(State Pattern):允许对象在其内部状态改变时改变其行为,适用于运行时状态转换影响行为的场景。 4. 命令模式(Command Pattern):将请求封装为对象,从而允许参数化客户端,并支持可撤销操作。在WinForms中,菜单命令、按钮点击等都可以使用命令模式。 5. 工厂方法模式(Factory Method Pattern)或抽象工厂模式(Abstract Factory Pattern):在运行时创建对象,而不需要指定具体类。 6. 装饰者模式(Decorator Pattern):动态地给对象添加额外的职责,比继承更灵活。 下面我们重点介绍几个在WinForms中特别有用的模式,并给出示例代码。 ### 1. 观察者模式(事件机制) WinForms内置支持观察者模式,通过事件和委托实现。例如,我们可以为一个按钮的点击事件添加多个处理程序,并在运行时动态添加或移除。 ```csharp button1.Click += new EventHandler(Button1_Click); // 订阅 button1.Click -= Button1_Click; // 取消订阅 ``` ### 2. 策略模式 假设我们有一个排序功能,需要在运行时选择不同的排序策略。 ```csharp // 策略接口 public interface ISortStrategy { void Sort(List<int> list); } // 具体策略:快速排序 public class QuickSortStrategy : ISortStrategy { public void Sort(List<int> list) { // 实现快速排序 } } // 具体策略:冒泡排序 public class BubbleSortStrategy : ISortStrategy { public void Sort(List<int> list) { // 实现冒泡排序 } } // 使用策略的上下文 public class Sorter { private ISortStrategy _strategy; public Sorter(ISortStrategy strategy) { _strategy = strategy; } public void SetStrategy(ISortStrategy strategy) { _strategy = strategy; } public void Sort(List<int> list) { _strategy.Sort(list); } } // 在WinForms中使用 private void btnSort_Click(object sender, EventArgs e) { ISortStrategy strategy; if (rbQuickSort.Checked) strategy = new QuickSortStrategy(); else strategy = new BubbleSortStrategy(); var sorter = new Sorter(strategy); sorter.Sort(data); } ``` ### 3. 状态模式 例如,一个订单对象可能有不同的状态(新建、已确认、已发货等),每个状态下处理订单的行为不同。 ```csharp public interface IOrderState { void ProcessOrder(Order order); } public class NewOrderState : IOrderState { public void ProcessOrder(Order order) { // 处理新订单 } } public class ConfirmedOrderState : IOrderState { public void ProcessOrder(Order order) { // 处理已确认的订单 } } public class Order { public IOrderState CurrentState { get; set; } public Order() { CurrentState = new NewOrderState(); } public void Process() { CurrentState.ProcessOrder(this); } } ``` ### 4. 命令模式 在WinForms中,我们可以将按钮点击等操作封装为命令对象,支持撤销和重做。 ```csharp public interface ICommand { void Execute(); void Undo(); } public class OpenFileCommand : ICommand { private string _filePath; public OpenFileCommand(string filePath) { _filePath = filePath; } public void Execute() { // 打开文件 } public void Undo() { // 撤销打开文件的操作(如关闭文件) } } // 在按钮点击事件中 private void btnOpen_Click(object sender, EventArgs e) { ICommand command = new OpenFileCommand("test.txt"); command.Execute(); // 将命令加入历史记录以便撤销 } ``` ### 5. 工厂模式 运行时根据条件创建对象。 ```csharp public interface IShape { void Draw(Graphics g); } public class Circle : IShape { public void Draw(Graphics g) { g.DrawEllipse(Pens.Black, 0, 0, 100, 100); } } public class Rectangle : IShape { public void Draw(Graphics g) { g.DrawRectangle(Pens.Black, 0, 0, 100, 50); } } public static class ShapeFactory { public static IShape CreateShape(string shapeType) { switch (shapeType) { case "Circle": return new Circle(); case "Rectangle": return new Rectangle(); default: throw new ArgumentException(); } } } // 使用 private void btnCreateShape_Click(object sender, EventArgs e) { IShape shape = ShapeFactory.CreateShape(cmbShapeType.SelectedItem.ToString()); shape.Draw(this.CreateGraphics()); } ``` ### 6. 装饰者模式 动态添加功能。例如,我们有一个基本的文本框,然后可以动态添加滚动条、边框等装饰。 ```csharp public abstract class TextBox { public abstract void Draw(); } public class BasicTextBox : TextBox { public override void Draw() { // 绘制基本文本框 } } public abstract class TextBoxDecorator : TextBox { protected TextBox _textBox; public TextBoxDecorator(TextBox textBox) { _textBox = textBox; } public override void Draw() { _textBox?.Draw(); } } public class ScrollableTextBox : TextBoxDecorator { public ScrollableTextBox(TextBox textBox) : base(textBox) { } public override void Draw() { base.Draw(); // 添加滚动条 } } // 使用 TextBox textBox = new BasicTextBox(); textBox = new ScrollableTextBox(textBox); // 动态添加滚动条 textBox.Draw(); ``` 以上这些模式都能在运行时动态改变应用的行为,非常适合WinForms应用程序。选择哪种模式取决于具体需求。 §§相关问题§§ 1. 在WinForms中如何实现观察者模式? 2. 策略模式和状态模式有什么区别? 3. 命令模式在WinForms中如何支持撤销操作? 4. 工厂模式在WinForms中有哪些应用场景? 5. 装饰者模式与继承相比有什么优势?</think>在 C# WinForms 应用程序中,以下设计模式特别适合**运行时动态实现**(即根据用户操作或程序状态动态调整行为),这些模式能有效管理界面与逻辑的交互: ### 1. **观察者模式 (Observer Pattern)** - **适用场景**:事件驱动交互(如按钮点击、数据变更通知) - **实现方式**:通过 C# 内置的 `event` 机制实现 - **优势**:解耦事件发布者和订阅者,支持运行时动态订阅/取消订阅 ```csharp // 定义事件发布者 public class DataModel { public event EventHandler DataChanged; private void OnDataChanged() => DataChanged?.Invoke(this, EventArgs.Empty); } // 窗体订阅事件(可运行时动态绑定) public partial class MainForm : Form { public MainForm(DataModel model) { model.DataChanged += (s, e) => UpdateUI(); } } ``` ### 2. **策略模式 (Strategy Pattern)** - **适用场景**:运行时切换算法或行为(如排序算法、导出格式) - **实现方式**:接口定义策略,运行时注入具体实现 ```csharp public interface IExportStrategy { void Export(DataGridView data); } // 运行时切换策略 public class ExportContext { private IExportStrategy _strategy; public void SetStrategy(IExportStrategy strategy) => _strategy = strategy; public void ExecuteExport(DataGridView data) => _strategy?.Export(data); } // 使用示例 var exporter = new ExportContext(); exporter.SetStrategy(new CsvExportStrategy()); // 运行时切换为CSV导出 exporter.ExecuteExport(dataGridView1); ``` ### 3. **状态模式 (State Pattern)** - **适用场景**:对象行为随状态改变(如编辑模式/查看模式切换) - **实现方式**:状态接口 + 具体状态类 ```csharp public interface IUIState { void Handle(Form form); } public class EditState : IUIState { public void Handle(Form form) { form.Controls.OfType<TextBox>().ToList() .ForEach(t => t.Enabled = true); // 启用所有文本框 } } // 运行时切换状态 public class FormStateContext { public IUIState CurrentState { get; set; } public void ApplyState() => CurrentState?.Handle(ownerForm); } // 使用 context.CurrentState = new EditState(); context.ApplyState(); // 动态切换到编辑模式 ``` ### 4. **命令模式 (Command Pattern)** - **适用场景**:撤销/重做、菜单操作、异步任务 - **实现方式**:将请求封装为对象 ```csharp public interface ICommand { void Execute(); void Undo(); } public class SaveCommand : ICommand { private TextBox _textBox; private string _prevText; public void Execute() { _prevText = _textBox.Text; File.WriteAllText("save.txt", _textBox.Text); } public void Undo() => _textBox.Text = _prevText; } // 命令管理(支持运行时添加) List<ICommand> commandHistory = new List<ICommand>(); buttonSave.Click += (s, e) => { var cmd = new SaveCommand(txtContent); cmd.Execute(); commandHistory.Add(cmd); // 动态记录命令 }; ``` ### 5. **工厂方法模式 (Factory Method)** - **适用场景**:运行时动态创建控件或对象 ```csharp public Control CreateControl(ControlType type) { switch (type) { case ControlType.TextBox: return new TextBox { Dock = DockStyle.Top }; case ControlType.ComboBox: return new ComboBox { DataSource = GetItems() }; default: throw new ArgumentException(); } } // 运行时动态生成 panel1.Controls.Add(CreateControl(ControlType.ComboBox)); ``` ### 6. **中介者模式 (Mediator Pattern)** - **适用场景**:复杂UI组件间通信 - **实现方式**:通过中介对象协调交互 ```csharp public class FormMediator { public void Register(Control control, Action action) { ... } public void Notify(Control sender) { // 根据sender类型触发其他控件更新 if (sender is TextBox) UpdatePreview(); } } // 控件注册中介 textBox1.TextChanged += (s, e) => mediator.Notify(textBox1); ``` ### 选择建议 | **场景** | **推荐模式** | **优势** | |-----------------------------|---------------------|----------------------------------| | 事件通知/数据绑定 | 观察者模式 | 原生事件支持,低耦合 | | 动态切换算法 | 策略模式 | 避免条件分支,易扩展 | | 界面状态转换 | 状态模式 | 状态行为集中管理 | | 撤销/重做/宏命令 | 命令模式 | 封装操作历史 | | 运行时对象创建 | 工厂方法 | 隔离创建逻辑 | | 多控件复杂交互 | 中介者模式 | 减少组件间直接依赖 | > **关键实践**:在 WinForms 中优先使用 C# 语言特性(如事件、委托)简化模式实现,避免过度设计。对于数据绑定场景,可结合 `BindingSource` 组件提升效率[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值