vc idispatchimpl 怎么实例化_面试老是被单例模式,还总被问懵,怎么解决?

8f3b8038d3bd002ffdc04e678c6996f3.png

单例模式

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。

单例模式的实现:

1.饿汉模式:

饿汉模式的饿体现在只要类被加载,就会立即实例化Singleton实例,后续无论怎么操作,只要严格使用getInstance,就不会出现其他实例。

static class Singleton{
        private Singleton() {
        }
        private static Singleton instance = new Singleton();
        public static Singleton getInstance() {
            return instance;
        }
    }

2.懒汉模式:

懒汉模式的懒体现在类加载的时候并没有立刻实例化,等到调用getInstance的时候,才真的实例化。如果整个代码都没有调用getInstance,那么实例化的过程就被省略了。

static class  Singleton {
        private Singleton() {
        }
        private static Singleton instance = null;
        public static Singleton getInstance() {
            if(instance==null) {
                instance = new Singleton();
            }
            return instance;
        }
    }

3.两种实现方式效率的比较:

我们一般认为懒汉模式比饿汉模式效率高一点,饿汉模式有很大可能用不到实例化,就会做无用功,而懒汉模式就不会有这种可能,节省了实例化的开销。

4.线程安全的比较:

(1).对于饿汉模式来说,多线程调用getInstance的时候,由于instance只初始化了一次,多线程对instance并不会涉及到修改,最多只是多次读取,所以饿汉模式是安全的。
(2).对于懒汉模式来说,getInstance中做了,读取instance内容,判断是否为空,如果instance为空就new实例,最后返回instance,这四件事情,这就涉及到多个线程同时修改一个对象,那么instance就有可能被new多次,也就是不能保证只实例化一次,所以懒汉模式是不安全的。

6e79c1df926d43e24376b7ac472b6544.png

5.对懒汉模式的三次优化

既然懒汉模式效率高,但是存在着线程不安全问题,怎么去优化值得我们可以放心的使用懒汉模式呢。
(1).加锁保证多线程安全
实例化的时候,给判空和new实例操作加上锁,确定在实例化的时候只能由一个线程实例化,当第二个线程再去操作的时候,实例已经存在,就不会再去new实例,保证原子性。

ecf1cffb10a9d6fadd98f59b9892ab4f.png

(2).判空提高效率
对于懒汉模式来说,只有在实例创建之前,存在线程不安全问题,当线程创建后,每次的getInstance都需要加锁解锁操作,而此时已经不需要了,这就会使得效率大大降低。

c29b6ba81b202b380230749b59756293.png

6c61eaa773a4a9ce1be0d76de6befd7e.png

(3)volatile保证内存可见性
当我们对懒汉模式进行上面的优化后,效率提高了,多线程也更安全了,但是还有一个的致命问题。多线程调用getInstance,先加速的在修改,后加锁的在读取,涉及到内存可见性问题。

(内存可见性指的是当cpu从内存中读取数据时,多次读取一个数据,cou会自动优化,不在从内存中读取而是直接读上次读到的数据,那么当这个数据在内存中被修改后,cpu并不知道,导致出错,而volatile可以保证cpu每次都从内从中读取数据)。

de9d7284e01c812d6f7de112ee678f28.png

最终代码:

static class  Singleton {
        private Singleton() {
        }
        private volatile static Singleton instance = null;
        public static Singleton getInstance() {
            if (instance==null) {
                synchronized (Singleton.class) {
                    if(instance==null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

总结:
单例模式是属于比较常见简单的设计模式,但是在面试中几乎都会被问到,把他分享给大家也是希望大家在面试的时候碰到不会一点准备都没有。

DISPID_WORKBOOK_CLOSE是Microsoft Office提供的一个事件,用于在关闭工作簿时触发。在C语言中使用该事件需要使用Microsoft Office提供的COM接口库。 以下是一个使用DISPID_WORKBOOK_CLOSE事件的C语言示例代码: ```c #include <windows.h> #include <ole2.h> #include <oleauto.h> #include <stdio.h> void __stdcall OnWorkbookClose(IDispatch* pWorkbook, VARIANT_BOOL* pCancel) { printf("Workbook is closing...\n"); } int main(int argc, char* argv[]) { CoInitialize(NULL); IDispatch* pExcelApp = NULL; IDispatch* pWorkbook = NULL; DISPID dispidWorkbookClose; DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 }; VARIANT_BOOL bCancel = VARIANT_FALSE; HRESULT hr; // 创建Excel应用程序对象 hr = CoCreateInstance(&CLSID_Application, NULL, CLSCTX_LOCAL_SERVER, &IID_IDispatch, (void**)&pExcelApp); if (FAILED(hr)) { printf("Failed to create Excel application object: %x\n", hr); goto cleanup; } // 打开指定的工作簿 VARIANT vtFilename; VariantInit(&vtFilename); vtFilename.vt = VT_BSTR; vtFilename.bstrVal = SysAllocString(L"C:\\test.xlsx"); hr = pExcelApp->Invoke(DISPID_Workbooks_Open, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &vtFilename, NULL, NULL); if (FAILED(hr)) { printf("Failed to open workbook: %x\n", hr); goto cleanup; } // 获取当前活动工作簿 VARIANT vtActiveWorkbook; VariantInit(&vtActiveWorkbook); hr = pExcelApp->Invoke(DISPID_Application_ActiveWorkbook, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispparamsNoArgs, &vtActiveWorkbook, NULL, NULL); if (FAILED(hr)) { printf("Failed to get active workbook: %x\n", hr); goto cleanup; } // 获取工作簿对象的IDispatch接口 pWorkbook = vtActiveWorkbook.pdispVal; // 获取Workbook对象的Close事件的DispID LPOLESTR szClose = L"Close"; hr = pWorkbook->GetIDsOfNames(IID_NULL, &szClose, 1, LOCALE_SYSTEM_DEFAULT, &dispidWorkbookClose); if (FAILED(hr)) { printf("Failed to get Workbook.Close DISPID: %x\n", hr); goto cleanup; } // 注册Workbook对象的Close事件处理函数 IConnectionPointContainer* pConnectionContainer; IConnectionPoint* pConnectionPoint; IUnknown* pUnknown = (IUnknown*)pWorkbook; hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionContainer); if (FAILED(hr)) { printf("Failed to get IConnectionPointContainer interface: %x\n", hr); goto cleanup; } hr = pConnectionContainer->FindConnectionPoint(IID_WorkbookEvents, &pConnectionPoint); if (FAILED(hr)) { printf("Failed to find IConnectionPoint interface: %x\n", hr); goto cleanup; } hr = pConnectionPoint->Advise((IDispatch*)new IDispatchImpl<OnWorkbookClose>, &dispidWorkbookClose, NULL); if (FAILED(hr)) { printf("Failed to advise IConnectionPoint interface: %x\n", hr); goto cleanup; } // 等待用户关闭工作簿 while (bCancel == VARIANT_FALSE) { Sleep(1000); } cleanup: if (pConnectionPoint) { pConnectionPoint->Unadvise(dispidWorkbookClose); pConnectionPoint->Release(); } if (pConnectionContainer) { pConnectionContainer->Release(); } if (pWorkbook) { pWorkbook->Release(); } if (pExcelApp) { pExcelApp->Release(); } CoUninitialize(); return 0; } ``` 以上代码演示了如何使用DISPID_WORKBOOK_CLOSE事件在C语言中处理Microsoft Excel工作簿关闭事件。代码中使用了Microsoft Office提供的COM接口库和C++ ATL库,其中IDispatchImpl是ATL库提供的一个模板类,用于实现COM接口。在实际使用中,还需要根据具体情况修改代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值