| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 378 人关注过本帖
标题:面向接口编程,分不多,但是绝对干货
只看楼主 加入收藏
rz250
Rank: 1
等 级:禁止访问
帖 子:4
专家分:0
注 册:2013-11-17
结帖率:0
收藏
 问题点数:0 回复次数:0 
面向接口编程,分不多,但是绝对干货
如何运用面向接口编程的方式设计一个 SocketUtil?
 
SocketUtil可以用于普通的长连接以及HTTP请求;主要是设计HTTP的接口或者抽象类,但是一定要给普通长连接留下开发余地,尽量满足开闭原则。
 
我已经做了一个,但是总感觉差点什么,主要是想不到哪些地方是将来可能会变的,或者如何以更方便扩展的方式去设计。
 
下面贴出我设计的 SocketUtil :
Java code
 
 
// ----------------- 接口 ----------------------
 
package com.liuwei.util.socket;
 
 
public interface SocketUtil {
 
    /**
     * 连接远端
     */
    public void connect( String remote, int port ) throws Exception;
     
    /**
     * 断开
     */
    public void disconnect();
     
    /**
     * 发送
     */
    public Object send( Object data )
            throws Exception;
}
 
// ----------------- 抽象 ----------------------
 
package com.liuwei.util.socket.impl;
 
import
import
import
import java.nio.channels.SocketChannel;
 
import com.liuwei.util.socket.SocketUtil;
 
public abstract class AbstractSocketUtil implements SocketUtil {
 
    protected SocketAddress remote;
    protected SocketChannel channel;
    protected String hostAddress;
    protected String uri;
 
    public void connect(String remote, int port) throws Exception {
        remote = this.format(remote);
        this.remote = new InetSocketAddress(this.hostAddress, port);
        this.channel = SocketChannel.open();
        this.channel.configureBlocking(false);
        this.channel.connect(this.remote);
        for (System.out.println("\n>> 开始连接: " + remote); true;) {
            System.out.println(">> .....");
            if (!this.channel.finishConnect()) {
                Thread.sleep(10);
            }
            else {
                System.out.println(">> 连接成功!");
                break;
            }
        }
    }
 
    public void disconnect() {
        try {
            if (channel.isOpen()) {
                channel.close();
            }
        } catch (IOException exception) {
        }
    }
 
    abstract protected String format(String address);
}
 
// ----------------- 具体实现:可以不看,没什么用 ----------------------
 
package com.liuwei.util.socket.impl;
 
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
 
import com.liuwei.util.socket.entity.HttpRequestData;
 
public class HttpSocketUtil extends AbstractSocketUtil {
 
    private String charset = "UTF-8";
 
    public HttpSocketUtil() {
 
    }
 
    public HttpSocketUtil(String charset) {
        this.charset = charset.isEmpty() ? "UTF-8" : charset;
    }
 
    public Object send(Object data) throws Exception {
        byte[] requestData = null;
        ByteBuffer buffer = null;
 
        requestData = this.buildRequestData(data).getBytes(this.charset);
        buffer = ByteBuffer.allocate(1024);
        buffer.put(requestData);
        buffer.flip();
        this.channel.write(buffer);
 
        return this.receive(this.channel, buffer);
    }
 
    protected String format(String address) {
        address = address.trim().replaceFirst("http://", "");
        address = address.trim().replaceFirst("https://", "");
 
        int index = address.indexOf("/");
        if (index == -1) {
            index = address.length();
            this.uri = "/";
        } else {
            this.uri = address.substring(index);
        }
        this.hostAddress = address.substring(0, index);
 
        return address;
    }
 
    private String receive(SocketChannel channel, ByteBuffer buffer)
            throws Exception {
        StringBuilder builder = new StringBuilder();
        long timeout = 5000;
        long timeoutStart = 0;
        int byteSize = 0;
 
        for (boolean startFlag = false; true;) {
            buffer.clear();
            int byteNum = this.channel.read(buffer);
 
            if (byteNum != 0) {
                startFlag = true;
                timeoutStart = 0;
                if (byteNum == -1) {
                    break;
                }
                byteSize += byteNum;
                buffer.flip();
                builder.append(new String(buffer.array(), this.charset));
            } else if ((byteNum == 0) && (startFlag)) {
                timeoutStart = (timeoutStart == 0) ? System.currentTimeMillis()
                        : timeoutStart;
                if ((System.currentTimeMillis() - timeoutStart) > timeout) {
                    break;
                }
                Thread.sleep(500);
            }
        }
 
        System.out.println(">> 本次读取到  " + byteSize / 1024 + "K 字节");
        return builder.toString();
    }
 
    private String buildRequestData(Object data) {
        if (data instanceof HttpRequestData) {
            return this.buildHttpRequestHead((HttpRequestData) data);
        }
        return null;
    }
 
    private String buildHttpRequestHead(HttpRequestData data) {
        String sessionIdKeyAndValue = data.getSessionIdKey() + "="
                + data.getSessionId();
        StringBuffer httpHead = new StringBuffer();
 
        httpHead.append("GET " + this.uri + " HTTP/1.1\r\n");
        httpHead.append("Host: " + this.hostAddress + "\r\n");
        httpHead.append("User-Agent:"
                + "Mozilla/5.0 (Windows NT 6.1; rv:22.0)\r\n");
        httpHead.append("Cookie: " + sessionIdKeyAndValue + "\r\n");
        httpHead.append("Connection: Keep-Alive\r\n");
        httpHead.append("\r\n");
        return httpHead.toString();
    }
 
}
 
 
 
// ----------------- 下面是今天心血来潮刚改的 ----------------//
 
// ----------------- 接口 ----------------------
 
package com.liuwei.util.socket;
 
 
public interface SocketUtil {
 
    /**
     * 连接远端
     */
    public void connect( String remote, int port ) throws Exception;
     
    /**
     * 断开
     */
    public void disconnect();
     
    /**
     * 发送
     */
    public Object send() throws Exception;
}
 
// ----------------- 还是接口 ----------------------
 
package com.liuwei.util.socket;
 
import java.util.Map;
 
public interface HttpUtil extends SocketUtil {
     
    /**
     * 使用默认端口连接远端(80)。
     * @param remote    这是URL,后面不要跟URI、端口。如果需要更改端口,可以使用:
     *                     connect( String remote, int port ) throws Exception
     *                     例如:http://www.baidu.com
     * @throws Exception 连接失败抛出异常。。。。
     */
    public void connect( String remote ) throws Exception;
     
    /**
     * 顾名思义,就是指定访问的服务器路径。
     * @param URI    Uniform Resource Identifier
     */
    public void setURI( String URI );
     
    /**
     * 指定HTTP请求头。
     * @param header
     */
    public void setHeader( Map<String, String> header );
     
    /**
     * 指定向服务器发送的内容。
     * @param content
     */
    public void setBody( String content );
     
}
注意看这里:
 
别那么吝啬,如果每个都能说出些干货,相互取经,说不定一个困惑多年的、怎么都想不明白的理论一下子就明白了,受益匪浅的。
 
很多东西,就算看人家先进的源码,也不一定明白。我写这个东西也是因为看Spring的源码,尤其是BeanFactory,好像有点感觉,但是模模糊糊的,理解不完全更讲不出来,很希望得到高人指点。
2013-11-18 21:11
快速回复:面向接口编程,分不多,但是绝对干货
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.020004 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved