单例模式
单例模式的优点:
1. 在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例,这样就防止了其他对象对自己的实例化,确保所有的对象都访问同一个实例
2. 单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性
3. 提供了对唯一实例的受控访问
4. 由于在系统内存中只存在一个对象,因此可以节约系统资源,当需要频繁创建和销毁对象时单例可以提高系统性能
5. 允许可变数目的单例
6. 避免对共享资源的多重占用
单例模式的缺点:
1. 不适用于变化的对象,如果同一个类型的对象总是要在不同的场景中发生变化,单例就会引起数据错误,不能保存彼此的状态
2. 由于单例模式中没有抽象层,因此单例类的扩展有很大困难
3. 单例类的职责过重,在一定程度上违背了“单一职责原则”。
4. 滥用单例会带来一些负面问题,如为了节约资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出,如果实例化的对象长时间不被利用,则系统会认为是垃圾而被回收,导致对象状态的丢失
使用单例的注意事项:
1. 使用时不能用反射模式创建单例,否则会实例化出一个新的对象
2. 使用单例模式的时候需要注意线程安全问题
3. 单例模式和懒单例模式的构造方法都是私有的,因此不能被继承
单例模式的适用场景:
单例 模式只允许创建一个对象,因此节省内存,加快对象的访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。
单例模式经典使用场景:
1. 资源共享的情况下,避免由于资源操作时导致的性能或损耗
2. 控制资源的情况下,方便资源之间的相互通信,如线程池等
策略模式
在策略模式中,一个类的行为或者其算法可以在运行时更改,例如:出游的时候可以乘坐火车,飞机,私家车或者自行车;超时促销可以使用打折,送商品,送积分等方法。
意图:定义一系列算法,把他们一个个封装起来,并且让它们可以相互替换
主要解决:在有多种算法相似的情况下,使用if...else所带来的复杂和难以维护
使用场景:如果一个系统中有许多类,而他们之间的区别仅在于他们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为
策略模式其实是对算法的包装,是把使用算法的责任与算法本身分割开,委派给不同的对象负责。策略模式将一系列算法包装在一系列策略中。
策略模式的类图:
策略模式分为三部分,分别为抽象策略角色(Strategy),具体策略角色(具体算法)和环境角色(Context类)。
抽象策略角色(Strategy):定义了所有支持的算法的公共接口,是一个抽象角色,通常由一个接口或抽象类实现
具体策略角色:封装了具体的算法或行为,继承于策略类
环境角色:持有一个Strategy类的引用,即该类使用一个ContextStrategy来配置,维护一个对具体策略的引用。
具体代码如下:
Strategy类:
/// <summary>
///抽象算法类
/// </summary>
public abstract class Strategy
{
public abstract void AlgorithmInterface();
}
具体策略角色A、B、C:
/// <summary>
///算法A类
/// </summary>
public class StrategyA:Strategy
{
/// <summary>
///算法A实现算法
/// </summary>
public override void AlgorithmInterface()
{
Console.WriteLine("算法A");
}
}
/// <summary>
///算法B类
/// </summary>
public class StrategyB:Strategy
{
/// <summary>
///算法A实现算法
/// </summary>
public override void AlgorithmInterface()
{
Console.WriteLine("算法B");
}
}
/// <summary>
///算法C类
/// </summary>
public class StrategyC:Strategy
{
/// <summary>
///算法C实现算法
/// </summary>
public override void AlgorithmInterface()
{
Console.WriteLine("算法C");
}
}
环境角色:
Class Context
{
Strategy st;
public Context(Strategy strategy )
{
this.st = strategy;
}
///<summary>
///上下文接口
///<summary>
public void ContextInterface()
{
st.AlgorithmInterface();
}
}
在环境角色中,使用了一个Strategy来保存实例化时选择的具体策略类型,由于为基类因此可以使用一个变量应对不同的情况。
测试策略A:
Context ct = new Context(new StrategyA());
ct.ContextInterface();
Console.ReadKey();
策略模式的优点:
1. 策略类之间可以自由切换,由于策略类都实现了同一个接口,所以使得它们之间可以自由切换
2. 易于扩展,增加一个新的策略只需要添加一个具体的策略类即可,不需要修改原有的代码
3. 避免使用很多的if..else,充分体现了面向对象设计思想
策略模式的缺点:
1. 客户端必须知道所有的策略类,并且自行决定使用哪一个策略类。
2. 策略模式会造成策略类过多。
代理模式(Proxy Mode)
提供一个代理者位置给一个对象,让代理者可以控制存取这个对象
代理模式多用于优化资源的加载,如果资源已经加载过了,就使用加载过的资源,否则开始加载,该过程由代理模式控制。
代理模式就像是一个过滤器,只有在一定条件下才可以执行一定的代码,这个条件可以在外部控制,有点像策略模式的进阶。
//原来的功能类
public abstract class Subject {
public abstract void Request();
}
public class RealSubject : Subject {
public RealSubject() { }
public override void Request()
{
Debug.Log("RealSubject.Request");
}
}
//代理
public class Proxy : Subject {
RealSubject m_RealSubject = new RealSubject();
public bool ConnectRemote { get; set; }
public Proxy() { }
public override void Request()
{
if (ConnectRemote)
m_RealSubject.Request();
else
Debug.Log("Proxy.Request");
}
}
//测试类
public class TestProxy {
void UnitTest() {
Proxy theProxy = new Proxy();
theProxy.Request();
theProxy.ConnectRemote = true;
theProxy.Request();
}
}
观察者模式(Observer)
观察者模式又被称为发布/订阅模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当这个主题对象在状态发生变化的时候,通知所有观察者对象,让它们自动更新自己。
将一个系统分割成一些类进行相互协作有不好的副作用,就是需要维护相关对象之间的一致性。我们不希望为了维持一致性让个各类之间紧密耦合,会带来很多的不便,观察者模式可以解决这一类的耦合关系。
观察者模式中的角色:
1. 抽象主题(Subject):将所有观察者对象的引用保存到一个聚集中,每个主题都可以有任何数量的观察者,抽象主题提供也给接口,可以增加和删除观察者对象。
2. 具体主题(ConcreteSubject):将有关状态存入具体观察者对象,在具体主题内部状态改变的时候给所有登记过的观察者发送通知。
3. 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知的时候更新自己。
4. 具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便本身的状态与主题状态协调。
观察者模式代码:
/// <summary>
/// 抽象主题类
/// </summary>
public abstract class Subject
{
private IList<Observer> observers = new List<Observer>();
/// <summary>
/// 增加观察者
/// </summary>
/// <param name="observer"></param>
public void Attach(Observer observer)
{
observers.Add(observer);
}
/// <summary>
/// 移除观察者
/// </summary>
/// <param name="observer"></param>
public void Detach(Observer observer)
{
observers.Remove(observer);
}
/// <summary>
/// 向观察者(们)发出通知
/// </summary>
public void Notify()
{
foreach (Observer o in observers)
{
o.Update();
}
}
}
/// <summary>
/// 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己
/// </summary>
public abstract class Observer
{
public abstract void Update();
}
/// <summary>
/// 具体观察者或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
/// </summary>
public class ConcreteSubject : Subject
{
private string subjectState;
/// <summary>
/// 具体观察者的状态
/// </summary>
public string SubjectState
{
get { return subjectState; }
set { subjectState = value; }
}
}
/// <summary>
/// 具体观察者,实现抽象观察者角色所要求的更新接口,已是本身状态与主题状态相协调
/// </summary>
public class ConcreteObserver : Observer
{
private string observerState;
private string name;
private ConcreteSubject subject;
/// <summary>
/// 具体观察者用一个具体主题来实现
/// </summary>
public ConcreteSubject Subject
{
get { return subject; }
set { subject = value; }
}
public ConcreteObserver(ConcreteSubject subject, string name)
{
this.subject = subject;
this.name = name;
}
/// <summary>
/// 实现抽象观察者中的更新操作
/// </summary>
public override void Update()
{
observerState = subject.SubjectState;
Console.WriteLine("The observer's state of {0} is {1}", name, observerState);
}
}
客户端代码:
class Program
{
static void Main(string[] args)
{
// 具体主题角色通常用具体自来来实现
ConcreteSubject subject = new ConcreteSubject();
subject.Attach(new ConcreteObserver(subject, "Observer A"));
subject.Attach(new ConcreteObserver(subject, "Observer B"));
subject.Attach(new ConcreteObserver(subject, "Observer C"));
subject.SubjectState = "Ready";
subject.Notify();
Console.Read();
}
}
观察者模式的适用场景:
当一个变量的改变需要改变其他对象,并且不确定有多少个对象需要改变。
一个抽象类型有两个方面,一个方面依赖于另一个方面,这时候使用观察者模式可以将两者封装在独立的对象中使它们各自独立地改变与复用。
其他模式待更新