常用三大设计模式——单例,工厂和观察者模式

本博客内容:
一、单例模式
二、工厂模式
三、观察者模式

装饰者模式
适配器模式
代理模式

设计模式不是高深技术,奇技淫巧,只是一种设计思想,针对不同的业务场景,最本质的目的是解耦,为了可扩展性和健壮性。

一、单例模式

参考: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<IMonitor> listMonitor { get;set;} //定义观察者集合,因为多个观察者观察一个对象,这里用集合
            string SubjectState { get; set;} //被观察者的状态
            void AddMonitor(IMonitor monitor); //添加一个观察者
            void RemoveMonitor(IMonitor monitor); //移除一个观察者
            void SendMessage();  //向所有观察者发消息
        }
        class Subject :IObject
        {
            list<IMonitor> listMonitor=new lit<IMonitor>();
            string subjectState
            {
            get; set;//被观察者的状态
            } 
            list<IMonitor> 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);
                }   
        }
          
               
               
        • 讲解
          关键点1:每个观察者需要被保存到被观察者的集合中,并且被观察者提供添加和删除的方式
          再看互动关系:当添加一个观察者的时候,把被观察者对象以构造函数的形式传给了观察者。最后我让被观察者执行sendmessage方法,这时会触发所有观察者的update方法以更新状态。
          关键点2:倍观察者把自己传给观察者,当状态改变后,通过遍历或循环的方法逐个通知列表中的观察者
          关键点3:虽然解耦了观察者和被观察者的依赖,让各自的变化不大影响另一方的变化,但是这种解耦并不是很彻底,没有完全解除两者之间的耦合。
          关键点4:在事件中,订阅者和发布者之间是通过把事件处理程序绑定到委托,并不是把自身传给对方。所以解决了观察者模式中不完全解耦的问题。
          可能的问题:
          1。通过委托绑定方法来实现观察者模式,会有什么隐患?
          有的,通过+=去把方法绑定到委托,很容易忘记-=。如果只绑定不移除,这个方法会一直被引用。我们知道GC去回收的时候,只会处理没有被引用的对象,只要是还被引用的对象时不会被回收掉的。所以如果在长期不关闭的系统中(比如监控系统),大量的代码使用+=而不-=,运行时间长以后可能会内存溢出。
          2.事件,委托,观察者之间的关系
          委托是一种类型,事件是一种特殊的委托,观察者模式是一种设计模式,事件的机制是观察者模式的一种实现,其中订阅者和发布者通过委托实现协同工作。
          归纳:观察者模式的关键点
          上述4点已指出。
          注意:
          使用委托绑定方法时,需要注意移除方法,否则可能造成内存溢出。

          委托、事件、观察者模式理解的不够深入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值