自己写代码 HelloHi开发日记 六 掰开Ui和逻辑

我一直以为,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添加一个按钮,控制连接断开的。呃,日后再说吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值