zoukankan      html  css  js  c++  java
  • 单例模式和工厂模式(转)

    基本设计模式:单例模式和工厂模式代码实现

    单例模式

          单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。通常我们可以让一个全局变量使得一个对象被访问,但它不能阻止你实例化多个对象。一个最好的办法是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。

          也就是说,很多时候我们需要全局的对象,如一个工程中,数据库访问对象只有一个,这时,可以考虑使用单例模式。单例模式比全局对象好还包括:单例类可以继承,如下例中的C++代码。

         单例模式的关键点在于:构造函数私有,静态的GetInstance。

         另外,在C++中必须注意内存的释放。C++、Java、C#中还要注意多线程时的同步问题,另外在多线程可以以合适的方式保证共享变量仅初始化一次

    以下列出懒汉式的单例模式

    C++实现:

    复制代码
    class Singleton  
    {  
      public:  
        static Singleton * GetInstance()  
        {  
            if(NULL == m_pInstance)  
                m_pInstance = new Singleton();  
            return m_pInstance;  
        }  
        static void Release()                    //必须,否则会导致内存泄露   
        {  
            if(NULL != m_pInstance)  
            {  
                delete m_pInstance;  
                m_pInstance = NULL;  
            }  
        }  
          
       protected:  
         Singleton()  
         {  
             cout<<"C++ Singleton"<<endl;  
         };  
         static Singleton * m_pInstance;  
    }; 
    
    Singleton* Singleton::m_pInstance = NULL;  
      
    class SingleDraw:public Singleton  
    {  
    public:  
        static SingleDraw* GetInstance()  
        {  
            if(NULL == m_pInstance)  
                m_pInstance = new SingleDraw();  
            return (SingleDraw*)m_pInstance;  
        }  
    protected:  
        SingleDraw()  
        {  
            cout<<"C++ SingleDraw"<<endl;  
        }  
    };  
      
    int main()  
    {  
        SingleDraw* s1 = SingleDraw::GetInstance();  
        SingleDraw* s2 = SingleDraw::GetInstance();  
        s2->Release();  
        return 0;  
    }  
    复制代码

    Java实现(这里仅给出类实现部分):

    复制代码
    public class Singleton{
    
         private static Singleton instance=NULL;
         
         private Singleton(){
              System.out.println("Java Singleton");
         }
    
         public static Singleton getInstance(){
              if(instance == NULL)
                   instance = new Singleton();
              return instance;
         }
    }
    复制代码


    还有另一种形式: 饿汉单例,也就是,类被加载的时候就已经创建好了单例,相比懒汉式只是加载new的地方发生了改变,这里代码重略

    饿汉式和懒汉式的比较:

    1 饿汉式单例,由于类被加载的时候就将自己实例化,所以,从资源利用的角度来说,饿汉式单例比懒汉式单例效率更差

    2 懒汉式单例在实例化的时候,必须处理好多个线程同时引用造成的访问限制问题.也就是,很有可能有两个线程同时去调用了这个获取单例的方法,造成了单例被创建了多次懒汉式单例模式线程安全问题:假如现在有两个线程A和线程B,线程A执行到 this.singletonPattern = new SingletonPattern(),正在申请内存分配,可能需要0.001微秒,就在这0.001微秒之内,线程B执行到if(this.singletonPattern == null),你说这个时候这个判断条件是true还是false?是true,那然后呢?线程B也往下走,于是乎就在内存中就有两个SingletonPattern的实例了。所以,在编写懒汉式单例模式时,应注意线程安全问题(由全局变量及静态变量引起的),这里可以用互斥同步的方式去解决。(面试可考的地方)

    饿汉式单例类可以在Java 语言内实现, 但不易在C++ 内实现因为静态初始化在C++ 里没有固定的顺序,因而静态的m_instance 变量的初始化与类的加载顺序没有保证,可能会出问题。这就是为什么GoF 在提出单例类的概念时,举的例子是懒汉式的。他们的书影响之大,以致Java 语言中单例类的例子也大多是懒汉式的

    工厂模式

    首先需要说一下工厂模式。工厂模式根据抽象程度的不同分为三种:简单工厂模式(也叫静态工厂模式)、这里所讲述的工厂方法模式、以及抽象工厂模式。工厂模式是编程中经常用到的一种模式。它的主要优点有:

    • 可以使代码结构清晰,有效地封装变化。在编程中,产品类的实例化有时候是比较复杂和多变的,通过工厂模式,将产品的实例化封装起来,使得调用者根本无需关心产品的实例化过程,只需依赖工厂即可得到自己想要的产品。
    • 对调用者屏蔽具体的产品类。如果使用工厂模式,调用者只关心产品的接口就可以了,至于具体的实现,调用者根本无需关心。即使变更了具体的实现,对调用者来说没有任何影响。
    • 降低耦合度。产品类的实例化通常来说是很复杂的,它需要依赖很多的类,而这些类对于调用者来说根本无需知道,如果使用了工厂方法,我们需要做的仅仅是实例化好产品类,然后交给调用者使用。对调用者来说,产品所依赖的类都是透明的。

    C++实现:

    复制代码
    #include <iostream>
    
    using namespace std;
    
    class IProduct
    {
    public:
        virtual void productMethod() = 0;
    };
    
    
    class Product:public IProduct
    {
    public:
        void productMethod() 
        {  
            cout<<"C++ productMethod call"<<endl;  
        }  
    };
    
    
    class IFactory { public: virtual IProduct* CreateProduct() = 0; };
    class ConcreateFactory:public IFactory { public: IProduct* CreateProduct() { IProduct* p = new Product(); return p; } }; int main() { IFactory* pFactory = new ConcreateFactory(); IProduct* p = pFactory->CreateProduct(); p->productMethod(); delete p; return 1; }
    复制代码


    Java实现

    复制代码
    interface IProduct {  
        public void productMethod();  
    }  
      
    
    class Product implements IProduct { public void productMethod() { System.out.println("Java productMethod call"); } }
    interface IFactory { public IProduct createProduct(); }
    class Factory implements IFactory { public IProduct createProduct() { return new Product(); } }
    public class Client { public static void main(String[] args) { IFactory factory = new Factory(); IProduct prodect = factory.createProduct(); prodect.productMethod(); } }
    愿你我既可以朝九晚五,也可以浪迹天涯;愿你我既可以拈花把酒,也能围炉诗书茶。
  • 相关阅读:
    Combine 框架,从0到1 —— 4.在 Combine 中使用计时器
    Combine 框架,从0到1 —— 4.在 Combine 中使用通知
    Combine 框架,从0到1 —— 3.使用 Subscriber 控制发布速度
    Combine 框架,从0到1 —— 2.通过 ConnectablePublisher 控制何时发布
    使用 Swift Package Manager 集成依赖库
    iOS 高效灵活地配置可复用视图组件的主题
    构建个人博客网站(基于Python Flask)
    Swift dynamic关键字
    Swift @objcMembers
    仅用递归函数操作逆序一个栈(Swift 4)
  • 原文地址:https://www.cnblogs.com/xiaoheihei/p/6487077.html
Copyright © 2011-2022 走看看