<监听器模式>在C++ 与 Java 之间实现的差异

来源:互联网 发布:ios11蜂窝移动网络搜索 编辑:程序博客网 时间:2024/06/15 16:13

前言:

        关于各种语言孰优孰劣的讨论在软件界就是个没完没了的话题,今天我决定也来掺和下。不过我想探讨的不是哪种语言的性能如何,钱途如何,而是站在语言本身特性的基础上中肯地比较探讨。因为现在工作用的是C/C++, 以前接触过Java,于是我就以这两门语言作为我的对比语言。


本文目的:

        我就以监听器的实现为例演示各自的实现代码,认识下Java与C++的代码风格,看看Java是如何滋润地生活在无指针的环境下,瞄瞄指针在C++中又有如何妙用?


场景设计:

        以监听器模式为例,现在有一个Window, Windows里面有一个按钮(按钮有检测点击的函数),当用户点击按

钮时,Windows能提供一个方法处理被点击的事件。

伪代码:

类 Window{  

Button 

 处理按钮被点击函数(){};

}

类 Button

{   

检测按钮被点击函数(){ 若点击,则回调处理函数 }

}

来看看类图设计

来看Java的典型实现:

/* * 事件监听 */public interface IOnClickListener{public void OnClicked();}/* * 按钮类 */public class CMyButton{private IOnClickListener m_listener = null;boolean setOnClickListener(IOnClickListener e){if(m_listener == null){m_listener = e;return true;}else{return false;}}//这个方法只提供给系统底层调用void click(){if (m_listener != null){m_listener.OnClicked();}}}/* *  Window类 */public class CMyWindow implements IOnClickListener{private String m_strWindowName = "<Defualt Windows>";protected CMyButton m_myButton;public CMyWindow(String strName){m_strWindowName = strName;m_myButton = new CMyButton();}//设置监听器,CMyWindow已经实现了OnClicked,所以事件触发时会回调本类的OnClicked()public void Init(){m_myButton.setOnClickListener(this);}@Overridepublic void OnClicked() {System.out.println(m_strWindowName+"'s button is clicked");}}public static void main(String args[]){CMyWindow win1 = new CMyWindow("Win1");win1.Init();/* * 这里模拟Button点击,其实应该由其内部 * 底层触发,这里为了方便演示,直接触发 */win1.m_myButton.click();} 


看看C++采用这种方式的实现:

//============================================================================// Name        : TestHandler.cpp// Author      : // Version     :// Copyright   : Your copyright notice// Description : Hello World in C++, Ansi-style//============================================================================#include <stdio.h>#include <iostream>#include <string>using namespace std;class IOnClickListener{public:virtual void OnClicked() = 0;};class CMyButton{public:CMyButton():m_listener(nullptr){};bool setOnClickListener(IOnClickListener* e){if(m_listener != nullptr){return false;}else{m_listener = e;return true;}};//这个方法只提供给系统底层调用void click(){if (m_listener != nullptr){m_listener->OnClicked();}}private:IOnClickListener* m_listener;};class CMyWindow : public IOnClickListener{public:CMyWindow(string strName): m_strWindowName(strName){};//设置监听器,CMyWindow已经实现了OnClicked,所以事件触发时会回调本类的OnClicked()void Init(){m_myButton.setOnClickListener(this);};//@Overridevirtual void OnClicked(){cout<<m_strWindowName+"'s button is clicked"<<endl;};CMyButton m_myButton;private:string m_strWindowName;};int main() {CMyWindow win1("Win1");win1.Init();win1.m_myButton.click();return 0;}


 C++和Java的代码大致差不多,比较显眼的差异在于在Button中 Java采用监听器对象,而C++采用监听器指针。皆因Java的对象能实现多态, 而C++只有指针可以实现多态。


疑问这里有人有疑问了? 

 这里一个window只有一个button可以通过 CMyWindow 实现监听器IOnClickListener接口OnClicked设置监听器,倘若一个window包括多个button,如何为每个button 在CMyWindow 中实现处理函数??OnClicked接口总不能在一个类中被实现多次吧 ~~


得意java说:一个类不能对一个接口实现多次,那我建立多个内部类可以了吧,况且我的匿名内部类可以简单又

简洁的哦~



public void Init(){m_myButton1.setOnClickListener(new IOnClickListener(){@Overridepublic void OnClicked() {System.out.println("button1 is clicked");}});m_myButton2.setOnClickListener(new IOnClickListener(){@Overridepublic void OnClicked() {System.out.println("button2 is clicked");}});}



奋斗C++说:我没有匿名内部类,可我也有内部类(有类名,跟普通类无异),但我不可能为了每个button新建一个内部类吧? 我有更灵活的方法,就是类函数指针。我只需要在CWindow里面为每个button添加相应的处理方法,方法的参数和返回值跟 OnClicked回调函数一样,另外在监听器接口中加上模版的特性也可以实现。




//用于定义处理函数的接口class IOnClickListener{public:virtual void OnClicked() = 0;};//实现监听器接口,加入模版指针和类成员指针用于识别  ->回调函数是属于哪个类的哪个方法template <class T>class COnClickListenerImpl : public IOnClickListener{public:typedef void (T::*OnClickListenHandler)();bool setOnClickHandler(T* p, OnClickListenHandler f){m_callObj = p;m_callBackFun = f;return true;}virtual void OnClicked(){(m_callObj->*m_callBackFun)();//调用类函数指针实现回调}private:T* m_callObj;//回调函数所在的对象指针OnClickListenHandler m_callBackFun;//回调函数的类成员指针};class CMyButton{public:CMyButton():m_listener(nullptr){};template<class T>bool setOnClickHandler(T* p, typename COnClickListenerImpl<T>::OnClickListenHandler f){COnClickListenerImpl<T>* tmp = new COnClickListenerImpl<T>();tmp->setOnClickHandler(p, f);m_listener = tmp;};//这个方法只提供给系统底层调用void click(){if (m_listener != nullptr){m_listener->OnClicked();}}private:IOnClickListener* m_listener;};class CMyWindow{public:CMyWindow(string strName): m_strWindowName(strName){};void Init(){//为两个按钮分别设置本类的两个处理函数m_myButton1.setOnClickHandler(this, &CMyWindow::OnBtn1Clicked);m_myButton2.setOnClickHandler(this, &CMyWindow::OnBtn2Clicked);};void OnBtn1Clicked(){cout<<m_strWindowName+"'s button1 is clicked"<<endl;};void OnBtn2Clicked(){cout<<m_strWindowName+"'s button1 is clicked"<<endl;};CMyButton m_myButton1;CMyButton m_myButton2;private:string m_strWindowName;};


总结:

        Java的匿名内部类对监听器的实现既暴力又简单,没有类名,一个内部类只为生成一个特定的监听器对象, 一个对象对应一个Button,思路比较清晰,印证了java的设计基础是优雅简单,尽量让开发者一目了然,也正是如此,java才有众多fans.

       C++不用通过内部类的方式,而是通过添加成员方法的方式为每个button设置回调处理函数,而中间用到了模版,类函数指针, 通过模板技术构造一个中间监听器模板类,在设置监听回调函数时自动实例化模板类实例的对象,在Button中通过保存接口指针,利用多态性间接地指向实例化的模版类对象, 说起来比较拗口,实现起来稍微复杂间接,但是比较灵活,也从令一方面印证了C++是一门稍微复杂,但是灵活到什么事都可以干。


思考点:

        通过COnClickListenerImpl这个模板类来避免CMyButton成为模版类(若没有COnClickListenerImpl,只能在CMyButton中保存T* m_callbackObj,这样的CMyButton就会变味,跟初衷不同,所以设计要尽量避免修改CMyButton)


疑问: 

 这时候有C基础的朋友可能会迫不及待地说,干嘛用类函数指针,用C函数指针,然后随便定义几个全局函数或者静态函数不就行了(C函数指针在C++不能指向类普通成员函数)?然后在CMyButton中存放一个回调函数指针就行了,连什么OnClickListener这些类都不用定义了~


答疑

 当然,我想说这些方法也是可行的。但是这样的话你的回调函数就不能直接访问CMyWindow的资源了(因为不是类普通函数),想调的话还需要通过其他途径访问CMyWindow~ 而我们在回调函数里经常还需用到其类的其他属性,所以这里用到类函数指针还是比较方便。




 



0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 美图手机充电慢怎么办 酷派b770太卡怎么办 酷派手机出现无命令怎么办 华为荣耀4x卡怎么办 华为手机图案解锁忘了怎么办 xp电脑读不起u盘怎么办 在外国玩王者卡怎么办 华为p7忘记解锁密码怎么办 华为荣耀4x存储空间不足怎么办 红米4a内存不够怎么办 华为h60开不了机怎么办 华为荣耀4c内存不足怎么办 华为4c运行内存不足怎么办 华为手机总是显示内存不足怎么办 华为荣耀4x畅玩版内存不足怎么办 三星手机忘了解锁密码怎么办 荣耀8密码忘了怎么办 华为4x开不了机怎么办 华为指纹和密码解锁解不开怎么办 华为荣耀5x死机怎么办 华为荣耀开不了机怎么办 荣耀10开不了机怎么办 乐视pro3变砖了怎么办 手机升级后开不了机怎么办 华为g750开不了机怎么办 手机变砖怎么办插电没反应 变砖手机不通电怎么办 小米手机充电口坏了怎么办 小米2s尾插坏了怎么办 小米手机充电插口坏了怎么办 一条网线上两个亚马逊账号怎么办 加拿大28输20万怎么办 买家账户被亚马逊关闭余额怎么办 京东自营物流慢怎么办 京东退货不给退怎么办 刚付款不想要了怎么办 淘宝卖家拒绝退货退款怎么办 投诉不成立卖家怎么办 淘宝卖家被买家投诉卖假货怎么办 天猫三天未发货怎么办 天猫申请换货卖家不处理怎么办