自己写代码 HelloHi开发日记 六 掰开Ui和逻辑
2010-02-04 12:15
316 查看
我一直以为,WPF是把Ui和逻辑分开了,现在GWT的UiBinder几乎也在往这个方向走。xml里面是.ui,.java里面是逻辑。但是其实这所
谓的逻辑也还有层次之分。
很多东西都是如此,就好像原子,之所以取这个名字是以为他不能再分,而后来又发现了质子,中子。细看HiChatUi里
面的代码,基本上有两种,一种是在更新Ui,一种是在调用异步通信。这应该是一个承上启下的类。
WPF为了实现Ui和逻辑的分离必须引入数据绑定
这么个东西。他们想让Ui和逻辑分离,因此就很讨厌看到inputText=“”类似的代码。因为他身在逻辑的地盘,干的却是Ui的活。但是现在Ui不是
一成不变的,不是一个静态的xaml能表示的了的。想想Ui怎么变呢,一般来讲Ui是数据的外衣,因此把Ui绑定到数据,让Ui随着数据变化,也就不需要
在非标记语言的地盘调用代码来修改控件的属性。这一部分被藏起来,被绑定机制做了。那万一这个Ui比较疯癫,他的变化不是那么随着数据的意愿呢?啊,这要
看你怎样定义数据了。在非标记语言的地盘上,数据和Ui数据还是可以划江而治的。有些代码,虽然不是用标记语言写的,但是它完全为Ui而存,其中每一个字
段都可以在Ui上找到相应的位置。由他再和真正的数据,逻辑交互,就显得比较,呃,有弹性。
所以现在看到HiChatUi这么长,我就心
里痒。其实从一开始我就觉得我会需要一个表示客户端的类,一切逻辑在这里面进行,而且里面还会保存有所有聊天记录。只不过本着一切从简的想法先苟且让程序
跑起来再说。不过该做的总归是要做的,看看现在的程序,所有的聊天记录甚至在本地都没有留底的,update得到的新的信息,然后直接加到Ui上面去。看
着没问题,跑着也没问题,多少让人不放心,以后很可能需要在本地维持消息的记录,到时候这份记录放到哪里呢,总不能还放到这个姓Ui的HiChatUi里
吧。再说,我也很不满与现在的状态机,呃,其实现在根本没有状态机,打开页面,就开始了,连没连上人,都可以说话。至少要有三个状态,等人,聊天,散。这
些都要放到HiChatUi里我就要疯了。因此我需要一个client类。
那么client应该是Ui的一部分呢,还是Ui是
client的一部分呢?client这个名字可能让他看起来更像ui的宿主,但是我们往往都说灵魂是装在躯壳里面。因此我还是比较倾向于把client
作为Ui的一个字段。这样Ui处理用户触发的事件就可以调用client的相应方法。但是异步更新自然是client类里面的事,与Ui无关,更新完了如
何修改Ui呢。我脑子里突然冒出了好多种想法。一认为灵魂和肉体是平等的,Ui和client类同在EntryPoint里面被创建,互相包含一个引用。
这样Ui响应到用户事件可以调用到client进行通信,Ui作为一个纯粹的肉体,可以为所有的字段提供get方法,而异步通信的结果也可以调用Ui提供
的get方法得到ui对象进行更新。二呢承认灵魂和肉体的平等,觉得互相包含的结构是可以接受的,但是互相之间完全的透明是不可以的。ui可以提供必要地
接口来更新ui,但是为所有ui元素提供get方法是不可以的。三认为Ui应该完全包含client,然而client里面进行的一切Ui都无从知
道,Ui只能一次一次的update,查看client的现状,而决定要不要修改Ui,要怎样修改。换言之冷漠的Ui丝毫不关心发生过什么,只关心现在怎
么样了。
首先从结构上看Ui和client平等论2:1击败了三,然后我想别人都说我二,我就选二吧。老实说我觉得三也有可取之处,也许更适合那
种变化多是更改而不是增加的一类应用,或者那种每一帧不问历史把屏幕清空重画的那种应用。
更进一步的,二认为提供哪些接口取决于有哪些更新需要修
改Ui,而不取决于Ui有哪些元素。也就是说Ui提供哪些接口不应该由他自己决定。嗯~,如果你想套住一个类,让他实现一个接口。后来发现,一个
EventHandler接口比较好。因为在异步调用的结果里调用一个复杂的同步调用我想着觉得不妥。万一这个调用花了特别长的时间不知道会不会使得两个
Ui的修改同时在两个线程被执行。而event这个东西据我所知一般是添加到一个序列里,然后一个一个拿出来分配。跟进去看了看看到了queue这个词,
应该不会是玩我的吧。
添加HiChangedEventHandler
public interface
HiChangedEventHandler extends EventHandler{
void onMessageSent();
void onMessageUpdated();
void onStateChanged();
}
添
加HiChangedEvent
public class HiChangedEvent extends
GwtEvent<HiChangedEventHandler> {
public static
Type<HiChangedEventHandler> TYPE = new
Type<HiChangedEventHandler>();
public enum
EChangeType {
MessageSent,
MessageUpdated,
}
private EChangeType changeType;
public
HiChangedEvent(EChangeType changeType) {
this.changeType =
changeType;
}
@Override
protected void
dispatch(HiChangedEventHandler handler) {
switch (changeType)
{
case MessageSent:
handler.onMessageSent();
break;
case MessageUpdated:
handler.onMessageUpdated();
break;
}
}
@Override
public
com.google.gwt.event.shared.GwtEvent.Type<HiChangedEventHandler>
getAssociatedType() {
return TYPE;
}
}
然后修改
HiChatUi,使之实现HiChangedEventHandler接口,再新建HiChatClient,把原来的逻辑事务都转移到里面
public
class HiChatClient {
private HandlerManager handlerManager;
private int clientId = -1;
public int getClientId() {
return clientId;
}
private HelloServiceAsync
service = GWT.create(HelloService.class);
private int lastIndex =
0;
private static final int UPDATE_PERIOD = 500;
private Timer timer = new Timer() {
@Override
public void run() {
update();
}
};
private HiMessage[] newMessages;
public HiMessage[]
getNewMessages() {
return newMessages;
}
public HiChatClient() {
timer.scheduleRepeating(UPDATE_PERIOD);//ms
}
public void setEventHandler(HiChangedEventHandler handler) {
handlerManager = new HandlerManager(this);
handlerManager.addHandler(HiChangedEvent.TYPE, handler);
}
private void initClientId() {
service.getClientId(new AsyncCallback<Integer>() {
@Override
public void onFailure(Throwable caught) {
// TODO Auto-generated method stub
}
@Override
public void
onSuccess(Integer result) {
clientId = result;
}
});
}
private boolean
isUpdating = false;
private void update() {
if
(clientId == -1) {
initClientId();
} else {
if (!isUpdating) {
isUpdating = true;
service.updateMessage(clientId, lastIndex, new
AsyncCallback<HiMessage[]>() {
@Override
public void onFailure(Throwable caught) {
// TODO Auto-generated method stub
}
@Override
public void onSuccess(HiMessage[] result) {
if (result != null && result.length != 0) {
newMessages = result;
lastIndex += result.length;
handlerManager.fireEvent(new
HiChangedEvent(EChangeType.MessageUpdated));
}
isUpdating = false;
}
});
}
}
}
public void sendMessage(String input) {
if
(!input.isEmpty()) {
service.sendMessage(clientId, input,
new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
// TODO Auto-generated method stub
}
@Override
public void
onSuccess(Void result) {
handlerManager.fireEvent(new HiChangedEvent(EChangeType.MessageSent));
update();
}
});
}
}
}
再修改原来的HiChatUi
public class HiChatUi
extends Composite
implements
HiChangedEventHandler {
private static HelloHiUiUiBinder
uiBinder = GWT
.create(HelloHiUiUiBinder.class);
interface HelloHiUiUiBinder extends UiBinder<Widget, HiChatUi> {
}
private HiChatClient client;
@UiField
VerticalPanel contentPanel;
@UiField
TextArea inputText;
@UiField
ScrollPanel scrollPanel;
@UiField
Button
startButton;
public HiChatUi() {
initWidget(uiBinder.createAndBindUi(this));
}
public void setClient(HiChatClient client) {
this.client =
client;
}
@UiHandler("inputText")
void
onKeyPress(KeyPressEvent event) {
if (event.getCharCode() ==
KeyCodes.KEY_ENTER) {
String input = inputText.getText();
if (!input.isEmpty()) {
client.sendMessage(inputText.getText());
}
}
}
@Override
public void onMessageSent() {
inputText.setText("");
}
@Override
public void onMessageUpdated() {
HiMessage newMessages[] =
client.getNewMessages();
if (newMessages != null &&
newMessages.length != 0) {
for (HiMessage message :
newMessages) {
if (message.getClientId() ==
client.getClientId()) {
contentPanel.add(new
HiMessageUi("You:", message.getContent()));
} else {
contentPanel.add(new HiMessageUi("Stanger:",
message.getContent()));
}
}
scrollPanel.scrollToBottom();
}
}
@Override
public void onStateChanged() {
// TODO
Auto-generated method stub
}
}
暂时还没有实现
StateChanged。
接下来在Ui添加一个按钮,控制连接断开的。呃,日后再说吧。
谓的逻辑也还有层次之分。
很多东西都是如此,就好像原子,之所以取这个名字是以为他不能再分,而后来又发现了质子,中子。细看HiChatUi里
面的代码,基本上有两种,一种是在更新Ui,一种是在调用异步通信。这应该是一个承上启下的类。
WPF为了实现Ui和逻辑的分离必须引入数据绑定
这么个东西。他们想让Ui和逻辑分离,因此就很讨厌看到inputText=“”类似的代码。因为他身在逻辑的地盘,干的却是Ui的活。但是现在Ui不是
一成不变的,不是一个静态的xaml能表示的了的。想想Ui怎么变呢,一般来讲Ui是数据的外衣,因此把Ui绑定到数据,让Ui随着数据变化,也就不需要
在非标记语言的地盘调用代码来修改控件的属性。这一部分被藏起来,被绑定机制做了。那万一这个Ui比较疯癫,他的变化不是那么随着数据的意愿呢?啊,这要
看你怎样定义数据了。在非标记语言的地盘上,数据和Ui数据还是可以划江而治的。有些代码,虽然不是用标记语言写的,但是它完全为Ui而存,其中每一个字
段都可以在Ui上找到相应的位置。由他再和真正的数据,逻辑交互,就显得比较,呃,有弹性。
所以现在看到HiChatUi这么长,我就心
里痒。其实从一开始我就觉得我会需要一个表示客户端的类,一切逻辑在这里面进行,而且里面还会保存有所有聊天记录。只不过本着一切从简的想法先苟且让程序
跑起来再说。不过该做的总归是要做的,看看现在的程序,所有的聊天记录甚至在本地都没有留底的,update得到的新的信息,然后直接加到Ui上面去。看
着没问题,跑着也没问题,多少让人不放心,以后很可能需要在本地维持消息的记录,到时候这份记录放到哪里呢,总不能还放到这个姓Ui的HiChatUi里
吧。再说,我也很不满与现在的状态机,呃,其实现在根本没有状态机,打开页面,就开始了,连没连上人,都可以说话。至少要有三个状态,等人,聊天,散。这
些都要放到HiChatUi里我就要疯了。因此我需要一个client类。
那么client应该是Ui的一部分呢,还是Ui是
client的一部分呢?client这个名字可能让他看起来更像ui的宿主,但是我们往往都说灵魂是装在躯壳里面。因此我还是比较倾向于把client
作为Ui的一个字段。这样Ui处理用户触发的事件就可以调用client的相应方法。但是异步更新自然是client类里面的事,与Ui无关,更新完了如
何修改Ui呢。我脑子里突然冒出了好多种想法。一认为灵魂和肉体是平等的,Ui和client类同在EntryPoint里面被创建,互相包含一个引用。
这样Ui响应到用户事件可以调用到client进行通信,Ui作为一个纯粹的肉体,可以为所有的字段提供get方法,而异步通信的结果也可以调用Ui提供
的get方法得到ui对象进行更新。二呢承认灵魂和肉体的平等,觉得互相包含的结构是可以接受的,但是互相之间完全的透明是不可以的。ui可以提供必要地
接口来更新ui,但是为所有ui元素提供get方法是不可以的。三认为Ui应该完全包含client,然而client里面进行的一切Ui都无从知
道,Ui只能一次一次的update,查看client的现状,而决定要不要修改Ui,要怎样修改。换言之冷漠的Ui丝毫不关心发生过什么,只关心现在怎
么样了。
首先从结构上看Ui和client平等论2:1击败了三,然后我想别人都说我二,我就选二吧。老实说我觉得三也有可取之处,也许更适合那
种变化多是更改而不是增加的一类应用,或者那种每一帧不问历史把屏幕清空重画的那种应用。
更进一步的,二认为提供哪些接口取决于有哪些更新需要修
改Ui,而不取决于Ui有哪些元素。也就是说Ui提供哪些接口不应该由他自己决定。嗯~,如果你想套住一个类,让他实现一个接口。后来发现,一个
EventHandler接口比较好。因为在异步调用的结果里调用一个复杂的同步调用我想着觉得不妥。万一这个调用花了特别长的时间不知道会不会使得两个
Ui的修改同时在两个线程被执行。而event这个东西据我所知一般是添加到一个序列里,然后一个一个拿出来分配。跟进去看了看看到了queue这个词,
应该不会是玩我的吧。
添加HiChangedEventHandler
public interface
HiChangedEventHandler extends EventHandler{
void onMessageSent();
void onMessageUpdated();
void onStateChanged();
}
添
加HiChangedEvent
public class HiChangedEvent extends
GwtEvent<HiChangedEventHandler> {
public static
Type<HiChangedEventHandler> TYPE = new
Type<HiChangedEventHandler>();
public enum
EChangeType {
MessageSent,
MessageUpdated,
}
private EChangeType changeType;
public
HiChangedEvent(EChangeType changeType) {
this.changeType =
changeType;
}
@Override
protected void
dispatch(HiChangedEventHandler handler) {
switch (changeType)
{
case MessageSent:
handler.onMessageSent();
break;
case MessageUpdated:
handler.onMessageUpdated();
break;
}
}
@Override
public
com.google.gwt.event.shared.GwtEvent.Type<HiChangedEventHandler>
getAssociatedType() {
return TYPE;
}
}
然后修改
HiChatUi,使之实现HiChangedEventHandler接口,再新建HiChatClient,把原来的逻辑事务都转移到里面
public
class HiChatClient {
private HandlerManager handlerManager;
private int clientId = -1;
public int getClientId() {
return clientId;
}
private HelloServiceAsync
service = GWT.create(HelloService.class);
private int lastIndex =
0;
private static final int UPDATE_PERIOD = 500;
private Timer timer = new Timer() {
@Override
public void run() {
update();
}
};
private HiMessage[] newMessages;
public HiMessage[]
getNewMessages() {
return newMessages;
}
public HiChatClient() {
timer.scheduleRepeating(UPDATE_PERIOD);//ms
}
public void setEventHandler(HiChangedEventHandler handler) {
handlerManager = new HandlerManager(this);
handlerManager.addHandler(HiChangedEvent.TYPE, handler);
}
private void initClientId() {
service.getClientId(new AsyncCallback<Integer>() {
@Override
public void onFailure(Throwable caught) {
// TODO Auto-generated method stub
}
@Override
public void
onSuccess(Integer result) {
clientId = result;
}
});
}
private boolean
isUpdating = false;
private void update() {
if
(clientId == -1) {
initClientId();
} else {
if (!isUpdating) {
isUpdating = true;
service.updateMessage(clientId, lastIndex, new
AsyncCallback<HiMessage[]>() {
@Override
public void onFailure(Throwable caught) {
// TODO Auto-generated method stub
}
@Override
public void onSuccess(HiMessage[] result) {
if (result != null && result.length != 0) {
newMessages = result;
lastIndex += result.length;
handlerManager.fireEvent(new
HiChangedEvent(EChangeType.MessageUpdated));
}
isUpdating = false;
}
});
}
}
}
public void sendMessage(String input) {
if
(!input.isEmpty()) {
service.sendMessage(clientId, input,
new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
// TODO Auto-generated method stub
}
@Override
public void
onSuccess(Void result) {
handlerManager.fireEvent(new HiChangedEvent(EChangeType.MessageSent));
update();
}
});
}
}
}
再修改原来的HiChatUi
public class HiChatUi
extends Composite
implements
HiChangedEventHandler {
private static HelloHiUiUiBinder
uiBinder = GWT
.create(HelloHiUiUiBinder.class);
interface HelloHiUiUiBinder extends UiBinder<Widget, HiChatUi> {
}
private HiChatClient client;
@UiField
VerticalPanel contentPanel;
@UiField
TextArea inputText;
@UiField
ScrollPanel scrollPanel;
@UiField
Button
startButton;
public HiChatUi() {
initWidget(uiBinder.createAndBindUi(this));
}
public void setClient(HiChatClient client) {
this.client =
client;
}
@UiHandler("inputText")
void
onKeyPress(KeyPressEvent event) {
if (event.getCharCode() ==
KeyCodes.KEY_ENTER) {
String input = inputText.getText();
if (!input.isEmpty()) {
client.sendMessage(inputText.getText());
}
}
}
@Override
public void onMessageSent() {
inputText.setText("");
}
@Override
public void onMessageUpdated() {
HiMessage newMessages[] =
client.getNewMessages();
if (newMessages != null &&
newMessages.length != 0) {
for (HiMessage message :
newMessages) {
if (message.getClientId() ==
client.getClientId()) {
contentPanel.add(new
HiMessageUi("You:", message.getContent()));
} else {
contentPanel.add(new HiMessageUi("Stanger:",
message.getContent()));
}
}
scrollPanel.scrollToBottom();
}
}
@Override
public void onStateChanged() {
// TODO
Auto-generated method stub
}
}
暂时还没有实现
StateChanged。
接下来在Ui添加一个按钮,控制连接断开的。呃,日后再说吧。
相关文章推荐
- 自己写代码 - HelloHi开发流水账 一 先画个躯壳
- 自己写代码 - HelloHi开发流水账 二 先跑起来
- 自己写代码 - HelloHi开发流水账 三 别再那么二
- 自己写代码 - HelloHi开发流水账 四 不止是String
- 自己写代码 - HelloHi开发流水账 五 一枚臭虫
- 开发自己的UBB”代码“
- qt日记:使用UI里面的转到槽机制没有使用信号与槽的方式编写的代码运行稳定
- iOS 开发工具 打造自己的代码
- 在二次开发中怎么获取自己想要的那部分代码的位置
- 提供一个Windows mobile Native UI 程序,循序渐进开发,并附有代码!
- Android检测版本更新 实现逻辑,UI效果自己处理
- 为了给自己开发一个支持 fastcgi 的 http server 做准备。剥离了 nanoweb 的 fastcgi 接口部分代码。测试了下。 成功了
- 开发人员要对自己编写代码安全负责
- 【小试插件开发】给Visual Studio装上自己定制的功能来提高代码调试效率
- 【IOS 开发学习总结-OC-41】★★ios开发——代码控制 UI 界面与 UI 控件的自定义
- atitit.自己动手开发编译器and解释器(2) ------语法分析,语义分析,代码生成--attilax总结
- 自己总结的Unity3d RPG网络游戏 UI逻辑 框架(基于NGUI)
- [C#]一步一步开发自己的自动代码生成工具之三:代码生成引擎
- 第一行代码第二版(郭霖著)笔记之第三章(UI开发的点点滴滴)
- 关于IOS开发的一些有用的代码片段(别人总结和自己的)