本博客内容:
一、单例模式
二、工厂模式
三、观察者模式
装饰者模式
适配器模式
代理模式
设计模式不是高深技术,奇技淫巧,只是一种设计思想,针对不同的业务场景,最本质的目的是解耦,为了可扩展性和健壮性。
参考:http://blog.jobbole.com/109449/
关键点有4个:
1.私有构造函数
2.声明静态单例对象
3.构造单例之前要加锁
4.需要2次检查单例实例是否为空,分别在锁之前和锁之后
class Singleton{
private:
Singleton();
static Singleton * m_singleton=NULL;
static objcect obj=new object();
public:
Singleton & getSingleton()
{
if(m_singleton==NULL)
{
lock(obj)
{
if(m_singleton==NULL)
m_singleton=new Singleton();
}
}
return m_singleton;
}
可能的问题:
1.为何要检测2次?
有可能延迟或者缓存原因,造成构造多个实例,违反了单例的初衷。
2.构造函数能否公有化
不,单例类的构造函数必须私有化,单例类不能被实例化,只能被静态调用。
3.lock住的对象为什么要是object对象,可以是int型吗?
不行,锁住的必须是个引用类型,如果锁值类型,每个不同的线程在声明的时候值类型变量的地址都不一样,那么上个线程锁住的东西,下个线程进来会认为根本没有锁,相当于每次都锁了不同的门。而引用类型的变量地址是相同的,每个线程进来判断锁都是判断同一个地址,相当于锁在同一扇门,起到了锁的作用。
参考:http://blog.jobbole.com/109594/
核心功能:根据“需求”生产“产品”
核心思想:解耦“需求”“工厂”和“产品”。
实际上根据业务情景不同分为不同的实现方式。一般分3种:简单工厂、工厂、抽象工厂。
1.简单工厂
int prodNo;
class IProduct
{
public:
SimpleFactroy(int proNo)
{
this.prodNo=prodNo;
}
IProduct GetProduct()
{
switch(prodNo)
{
case 1:
return new ProductA();
case 2:
return new ProductB();
default:
return new ProductC();
}
}
}
//产品A
class ProductA: IProduct
{
//属性 ...
}
把产品类和工厂类分开,才是使用工厂模式的初衷。
简单工厂模式存在的问题:
比如来了新需求,D、E、F、G、H等,需要再switch case或者 if else中维护工厂中的判断语句,造成的后果就是可能这个工厂类会非常非常长,各种判断全部挤在一起,给扩展和维护带来麻烦,就是说,工厂和产品还没有完全解耦,绑定在一起的。得出结论:
简单工厂通过构造时传入的标识来生产产品,不同产品都在同一个工厂中生产,会随着产品的增加而增加,给扩展和维护带来麻烦。
引出工厂模式:
interface IFactroy //工厂接口
{
IProduct GetProduct();
}
//A工厂类
class FactroyA:IFactroy
{
IProduct productA;
public:
FactroyA()
{
this.productA=new ProductA();
}
IProduct GetProduct()
{
return this.productA; //A工厂生产A产品
}
}
...B同理 //B工厂生产B产品
//产品A
class ProductA: IProduct
{
//属性...
}
...其他产品
在上述代码中,已将工厂类分开,不再将所有产品都在同一工厂中生产,解决了简单工厂中不停的switch case问题。如果来了一个C产品,我们只需要写一个C工厂,一个C产品,在调用时用C工厂生产C产品即可,即A和B工厂和产品完全不受影响。
仍存在问题:
当业务需求是需要生产产品族的时候,工厂就不再适合了,何谓产品族和产品等级结构?举例:
三星的洗衣机、电视机、冰箱就是三星这个工厂的产品族。
产品等级结构:例如洗衣机的等级结构中有三星的、四门子的、LG、海尔、三菱等等
引出结论三:工厂模式无法解决产品族和产品等级结构的问题
//工厂接口 ,即抽象工厂
interface IFcatroy
{
IFridge CreateFridge();
IAirCondition CreateAirCondition();
}
//三星的工厂,生产三星的产品族
class SamsungFactory: IFactroy
{
public :
IAirCondition CreateAirCondition()
{
return new SamsungAirCondiction();//三星的工厂生产三星的空调
}
IFridge CreateFridge()
{
return new SamsungFridge(); //三星的工厂生产三星的冰箱
}
}
//类似以上,格力也有自己的工厂,生产格力的产品族
//接下来
//冰箱产品接口
interface IFridge
{
//冰箱产品接口,action
}
interface IAirCondition
{
//空调产品接口,action
}
class SamsungFridge:IFridge
{
//三星的冰箱...
}
//格力的冰箱...
可以看出,在工厂模式中,一个工厂生产一个产品,所有的具体产品都是由同一个抽象产品派生来的,不存在产品等级结构和产品族的概念;而在抽象工厂中,同一个等级的产品是派生于一个抽象产品(即产品接口),一个抽象工厂派生不同的具体工厂,每个具体工厂生产自己的产品族(包含不同产品等级)。
得出结论:
工厂模式中,一个工厂生产一个产品,所有产品派生于同一个抽象产品(或产品接口);而抽象工厂模式中,一个工厂生产多个产品,它们是一个产品族,不同的产品族的产品派生于不同的抽象产品(或产品接口)。
归纳时刻:
工厂模式其实是三种模式:
关键点如下:
一、实现越来越复杂
二、简单工厂通过构造时传入的标识来生产产品,不同产品都在同一个工厂中生产,这种判断会随着产品的增加而增加,给扩展和维护带来麻烦。
三、工厂模式无法解决产品族和产品等级结构的问题
四、抽象工厂模式中,一个工厂生产多个产品,它们是一个产品族,不同的产品族的产品派生于不同的抽象产品(或产品接口)。
可能遇到的问题:
1.何时使用工厂模式
根据具体业务需求,不要认为简单工厂是用switch case就一无是处,用设计模式是为了解决问题,根据三种模式的特质,以及对未来扩展的预期,来确定使用哪种工厂模式。
2.你在项目中工厂模式的应用
参考:http://blog.jobbole.com/109845/
设计模式三杰:单例、工厂、观察者
因为这三个使用频率最高、变化最多、覆盖面最广
有2个角色:观察者和被观察者
每个角色都对应一个类,比如观察者模式,肯定对应着一个观察者类,被观察者肯定对应的被观察者类。
那么设计模式实际上就是面向对象的特性。
逻辑上:一对多的依赖关系。
就像:守卫们盯着囚犯,一旦囚犯动,守卫们就必须马上采取行动。(守卫:观察者)。
一个系统中,实现这种一对多的而且之间有一定关联的逻辑的时候,由于需要保持他们之间的协同关系,
最简便的方法是采用紧耦合,把这些对象绑定到一起,这样一来,一旦有扩展或者修改的时候,开发人员所面对的难度非常大,而且很容易造成Bug,观察者模式就解决了该问题,在保持一系列观察者和观察者对象协同工作的同时,之间解耦。
//被观察者
public interface IObject
{
list listMonitor { get;set;} //定义观察者集合,因为多个观察者观察一个对象,这里用集合
string SubjectState { get; set;} //被观察者的状态
void AddMonitor(IMonitor monitor); //添加一个观察者
void RemoveMonitor(IMonitor monitor); //移除一个观察者
void SendMessage(); //向所有观察者发消息
}
class Subject :IObject
{
list listMonitor=new lit();
string subjectState
{
get; set;//被观察者的状态
}
list listMonitor
{
get{ return listMonitor;
listMonitor=vale;
}
}
void AddMonitor(IMonitor monitor)
{
list.add(monitor);
}
void removeMonitor(IMonitor monitor)
{
list.remove(monitor);
void SendMessage()
{
foreach(IMonitor m in listMonitor)
{
m.update();
}
}
}
//观察者
public :
interface IMonitor //定义观察者接口
{ void update();}
class Monitor:IMonitor
{
string monitorState="Stop!"; //观察者初始状态
string name; //名称,用于标记不同观察者
IObject subject; //被观察者对象
Monitor(IObject subject,string name) //构造观察者时,传入被观察者对象,以及表示该观察者名称
{
this.subject=subject;
this.name=name;
Console.WriteLine("我是观察者{0},我的初始状态是{1}",name,monitorState);
}
void Update() //当被观察者状态改变,观察者要随之改变
{
monitorState=subject.SubjectState;
Console.WriteLine("我是观察者{0},我的状态是{1}",name,monitorState);
}
}
//主函数中使用
void main()
{
IObject subject=new Subject();
subject.AddMonitor(new Monitor(subject,"Monitor_1"));
subject.AddMonitor(new Monitor(subject,"Monitor_2"));
subject.AddMonitor(new Monitor(subject,"Monitor_3"));
subject.SubjectState="Start!";
subject.SendMessage();
Console.Read();
}
}
讲解:
关键点1:每个观察者需要被保存到被观察者的集合中,并且被观察者提供添加和删除的方式
再看互动关系:当添加一个观察者的时候,把被观察者对象以构造函数的形式传给了观察者。最后我让被观察者执行sendmessage方法,这时会触发所有观察者的update方法以更新状态。
关键点2:倍观察者把自己传给观察者,当状态改变后,通过遍历或循环的方法逐个通知列表中的观察者
关键点3:虽然解耦了观察者和被观察者的依赖,让各自的变化不大影响另一方的变化,但是这种解耦并不是很彻底,没有完全解除两者之间的耦合。
关键点4:在事件中,订阅者和发布者之间是通过把事件处理程序绑定到委托,并不是把自身传给对方。所以解决了观察者模式中不完全解耦的问题。
可能的问题:
1。通过委托绑定方法来实现观察者模式,会有什么隐患?
有的,通过+=去把方法绑定到委托,很容易忘记-=。如果只绑定不移除,这个方法会一直被引用。我们知道GC去回收的时候,只会处理没有被引用的对象,只要是还被引用的对象时不会被回收掉的。所以如果在长期不关闭的系统中(比如监控系统),大量的代码使用+=而不-=,运行时间长以后可能会内存溢出。
2.事件,委托,观察者之间的关系
委托是一种类型,事件是一种特殊的委托,观察者模式是一种设计模式,事件的机制是观察者模式的一种实现,其中订阅者和发布者通过委托实现协同工作。
归纳:观察者模式的关键点
上述4点已指出。
注意:
使用委托绑定方法时,需要注意移除方法,否则可能造成内存溢出。
委托、事件、观察者模式理解的不够深入。