这两天看了看各招聘要求上写的东西,想到除了数据结构算法和数学还有设计模式也得好好突击一下。
今天先记两个之前项目经常用的单例模式和观察者模式。
单例模式
单例模式是对象创建型模式。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类并提供全局访问的方法。
即:单例类只能有一个实例;
单例类必须自己创建这个唯一的实例;
单例类必须给其它所有对象提供这一实例。
适用环境:想控制实例数目,节省系统资源的时候。
优点:因为内存中只有一个实例,所以减少了系统内存开销,尤其在频繁建立和销毁实例的时候;
避免对资源的多重占用。
缺点:没有接口,不能继承,扩展性差;
违背了“单一职责原则”,一个类应该只关心其内部逻辑,而不关心外部怎么实例化。
单线程实现:
class Singleton
{
private static Singleton instance;
private Singleton() {}
public static Singleton GetInstance()
{
if(instance == null)
{
instance = new Singleton();
}
return instance;
}
}
很多例子最开始给的都是上边那种写法,最基础的“懒汉式”,是一种线程不安全的形式,它不支持多线程,因为没有加锁。
下边这种称为“饿汉式”,也没有加锁,但是支持多线程,执行效率高:
class Singleton
{
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton GetInstance()
{
return instance;
}
}
但是饿汉式会产生垃圾对象,类加载的时候就初始化了对象,浪费内存。
加锁的方式支持多线程,执行效率虽然略低,但是安全:
class Singleton
{
private static Singleton instance;
private static readonly objcet locker = new object();
pritate Singleton() {}
public statice Singleton GetInstance()
{
lock(locker)
{
if(instance == null)
{
instance = new Singleton();
}
}
return instance;
}
}
由于上边的方法效率比较低,所以尽量用下边这种既安全效率又高的方法“双重锁定/双检锁”:
class Singleton
{
private static Singleton instance;
private static readonly object locker = new object();
private Singleton() {}
public static Singleton GetInstance()
{
//当第一个线程运行的时候会给locker加锁;
//当第二个线程运行的时候检测到locker是加锁状态的,就会挂起等待解锁;
//lock语句结束后会对locker解锁
/**lock住的表示括号里面对象的地址被第一个访问到这里的线程锁定,
如果下一个线程访问到这里,会检测该对象是否被释放,
如果没有被释放,则等待,如果已经被释放,则锁定然后再继续往后走。
这里所谓锁定该对象实际是锁定了该对象所对应的地址引用,
所以locker一定是objcet类型,不能是值类型,因为值类型地址每次都不一样。**/
if(instance == null)
{
lock(locker)
{
if(instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
观察者模式
刚看到这几个字的时候有点儿懵,看字面上的意思感觉和之前项目用的MVC模式很像,一Google发现,果然MVC就是应用了观察者模式,model相当于观察目标,view相当于观察者,controlller相当于二者之间的中介。
观察者模式是一种行为模式。定义对象一种一对多的依赖关系,当对象状态发生改变时,所有依赖它的对象都得到通知并自动更新。
优点:可独立改变观察者和被观察者,二者的关系是松耦合的;
观察者模式支持广播通信,被观察者会向所有注册过的观察者发送通知;
确定:如果一个被观察值拥有很多直接或间接的观察者,状态发生改变的时候通知到所有的观察者会很耗时间;
如果在观察者和被观察者之间存在循环依赖的话,被观察者会触发这种循环调用,会导致程序崩溃;
观察者模式没有相应的机制让观察者知道被观察者是怎样发生改变的,只知道发生了改变。
观察者模式包含“推”模式和“拉”模式,即由被观察目标向所有注册了的观察者推送消息,以及由观察者自身按需取消息。
例子:当用户从银行取钱后会收到银行发来的短信,这里银行就是目标,而用户就是观察者。
class Program
{
public delegate void NotifyEventHandler(object sender);
public class Bank
{
public event NotifyEventHandler NotifyEvent;
private static double _money;
private static Bank(double money)
{
this._money = money;
}
public double Money
{
get
{
return this._money;
}
}
public void WithDraw()
{
OnWithDrawChanged();
}
public void OnWithDrawChanged()
{
if(NotifyEvent != null)
{
NotifyEvent(this);
}
}
}
public class Client
{
private static int _phoneNumber;
private static Client(int phoneNumber)
{
this._phoneNumber = phoneNumber;
}
public void Update(object obj)
{
Bank bank = obj as Bank;
Console.WriteLine("Notified: Phone No. is {0}. Your Withdraw is {1:C}", this._phoneNumber, bank.Money);
}
}
static void Main(string[] args)
{
Bank bank = new Bank(500);
Client phone = new Client(123456);
bank.NotifyEvent += new NotifyEventHandler(phone.Update);
bank.WithDraw();
}
}