您的位置:首页 > 产品设计 > UI/UE

自己写代码 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添加一个按钮,控制连接断开的。呃,日后再说吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐