六大设计原则
(1)单一职责原则: 一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因
(2)依赖倒置原则: 依赖于抽象,高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象,其核心思想是:要面向接口编程,不要面向实现编程。
(3)里氏替换原则: 子类必须能够替换其基类,就是使用抽象和多态,所有引用基类(父类)的地方必须能透明地使用其子类的对象。只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。反过来,有子类出现的地方,父类未必就能适合
(4)接口隔离原则: 使用多个小的专门的接口,而不要使用一个大的总接口。(5)迪米特法则: 尽量减少类与类之间的联系一个软件实体应当尽可能少地与其他实体发生相互作用
(6)开放-封闭原则: 对于扩展是开放的,对于更改是封闭的,软件实体应尽量在不修改原有代码的情况下进行扩展
观察者模式🐱💻
观察者模式是一种行为设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。当一个对象的改变需要同时改变其他对象的时候,可以考虑使用观察者模式。
发布者(Publisher): 会向其他对象发送值得关注的事件。 事件会在发布者自身状态改变或执行特定行为后发生。 发布者中包含一个允许新订阅者加入和当前订阅者离开列表的订阅构架。
当新事件发生时, 发送者会遍历订阅列表并调用每个订阅者对象的通知方法。 该方法是在订阅者接口中声明的。
订阅者接口(Subscriber): 接口声明了通知接口。 在绝大多数情况下, 该接口仅包含一个 update更新方法。 该方法可以拥有多个参数, 使发布者能在更新时传递事件的详细信息。
具体订阅者(Concrete Subscribers):可以执行一些操作来回应发布者的通知。 所有具体订阅者类都实现了同样的接口, 因此发布者不需要与具体类相耦合。
订阅者通常需要一些上下文信息来正确地处理更新。 因此, 发布者通常会将一些上下文数据作为通知方法的参数进行传递。
发布者也可将自身作为参数进行传递, 使订阅者直接获取所需的数据。
客户端:(Client) 会分别创建发布者和订阅者对象, 然后为订阅者注册发布者更新。
观察者模式优缺点
优点:
- 可以支持多种不同的具体观察者实现,有利于程序的扩展
- 观察者的数目是可变的,主题可以实现动态的增加或移除观察者对象
- 开闭原则。 你无需修改发布者代码就能引入新的订阅者类 (如果是发布者接口则可轻松引入发布者类)。
- 你可以在运行时建立对象之间的联系。
缺点:
- 订阅者的通知顺序是随机的。
观察者模式适合应用场景
- 当一个对象状态的改变需要改变其他对象, 或实际对象是事先未知的或动态变化的时, 可使用观察者模式。
当你使用图形用户界面类时通常会遇到一个问题。 比如, 你创建了自定义按钮类并允许客户端在按钮中注入自定义代码,
这样当用户按下按钮时就会触发这些代码。 观察者模式允许任何实现了订阅者接口的对象订阅发布者对象的事件通知。 你可在按钮中添加订阅机制,
允许客户端通过自定义订阅类注入自定义代码。
- 当应用中的一些对象必须观察其他对象时, 可使用该模式。 但仅能在有限时间内或特定情况下使用
订阅列表是动态的, 因此订阅者可随时加入或离开该列表。
在 C# 中的使用
using System;
using System.Collections.Generic;
using System.Threading;
namespace RefactoringGuru.DesignPatterns.Observer.Conceptual
{
public interface IObserver
{
// Receive update from subject
void Update(ISubject subject);
}
public interface ISubject
{
// Attach an observer to the subject.
void Attach(IObserver observer);
// Detach an observer from the subject.
void Detach(IObserver observer);
// Notify all observers about an event.
void Notify();
}
// The Subject owns some important state and notifies observers when the
// state changes.
public class Subject : ISubject
{
// For the sake of simplicity, the Subject's state, essential to all
// subscribers, is stored in this variable.
public int State { get; set; } = -0;
// List of subscribers. In real life, the list of subscribers can be
// stored more comprehensively (categorized by event type, etc.).
private List<IObserver> _observers = new List<IObserver>();
// The subscription management methods.
public void Attach(IObserver observer)
{
Console.WriteLine("Subject: Attached an observer.");
this._observers.Add(observer);
}
public void Detach(IObserver observer)
{
this._observers.Remove(observer);
Console.WriteLine("Subject: Detached an observer.");
}
// Trigger an update in each subscriber.
public void Notify()
{
Console.WriteLine("Subject: Notifying observers...");
foreach (var observer in _observers)
{
observer.Update(this);
}
}
// Usually, the subscription logic is only a fraction of what a Subject
// can really do. Subjects commonly hold some important business logic,
// that triggers a notification method whenever something important is
// about to happen (or after it).
public void SomeBusinessLogic()
{
Console.WriteLine("\nSubject: I'm doing something important.");
this.State = new Random().Next(0, 10);
Thread.Sleep(15);
Console.WriteLine("Subject: My state has just changed to: " + this.State);
this.Notify();
}
}
// Concrete Observers react to the updates issued by the Subject they had
// been attached to.
class ConcreteObserverA : IObserver
{
public void Update(ISubject subject)
{
if ((subject as Subject).State < 3)
{
Console.WriteLine("ConcreteObserverA: Reacted to the event.");
}
}
}
class ConcreteObserverB : IObserver
{
public void Update(ISubject subject)
{
if ((subject as Subject).State == 0 || (subject as Subject).State >= 2)
{
Console.WriteLine("ConcreteObserverB: Reacted to the event.");
}
}
}
class Program
{
static void Main(string[] args)
{
// The client code.
var subject = new Subject();
var observerA = new ConcreteObserverA();
subject.Attach(observerA);
var observerB = new ConcreteObserverB();
subject.Attach(observerB);
subject.SomeBusinessLogic();
subject.SomeBusinessLogic();
subject.Detach(observerB);
subject.SomeBusinessLogic();
}
}
}
执行结果:
Subject: Attached an observer.
Subject: Attached an observer.
Subject: I'm doing something important.
Subject: My state has just changed to: 2
Subject: Notifying observers...
ConcreteObserverA: Reacted to the event.
ConcreteObserverB: Reacted to the event.
Subject: I'm doing something important.
Subject: My state has just changed to: 1
Subject: Notifying observers...
ConcreteObserverA: Reacted to the event.
Subject: Detached an observer.
Subject: I'm doing something important.
Subject: My state has just changed to: 5
Subject: Notifying observers...