<监听器模式>在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~ 而我们在回调函数里经常还需用到其类的其他属性,所以这里用到类函数指针还是比较方便。
- <监听器模式>在C++ 与 Java 之间实现的差异
- <监听器模式>在C++ 与 Java 之间实现的差异
- C/C++与Java的之间的差异
- JAVA学习笔记:基础算法(附Java与C之间检查数组越界的差异)
- 观察者模式实现java的文件监听器
- C标准之间的差异
- C语言中的空格符与结束符之间的差异
- c和java语言之间的差异(摘录)
- ++运算符在C/C++与C#/JAVA中的差异
- java监听器的原理与实现
- Java实现经理与员工的差异
- 【Java与C++之间的一些差异】之 方法重载
- Java监听器与观察者模式
- java 监听器的实现
- Objective C与Java之间的DES加解密实现
- 多线程安全的Singleton单件模式在C++,java与C#下的实现
- 【Html】XHTML 与 HTML 之间的差异
- jBPM5与Activiti之间的差异对比
- Eclipse 远程主机强迫关闭了…
- 我从创建四家技术公司中学到的事
- Eclipse开发前常用设置(转)
- iphone开发书籍
- mysql source命令
- <监听器模式>在C++ 与 Java 之间实现的差异
- web开发eclipse环境配置
- android如何通过wifi给指定的设备…
- ios开发中17个常用的小代码
- 搬家了
- iOS 实现简单的界面切换
- iOS学习用代码写界面,不用ib
- 菜鸟也能解决android中的OOM问题
- NSLog常用的代码