【讨论】面向接口编程,分不多,但是绝对干货
此贴只做学习交流用如何运用面向接口编程的方式设计一个 SocketUtil?
SocketUtil可以用于普通的长连接以及HTTP请求;主要是设计HTTP的接口或者抽象类,但是一定要给普通长连接留下开发余地,尽量满足开闭原则。
我已经做了一个,但是总感觉差点什么,主要是想不到哪些地方是将来可能会变的,或者如何以更方便扩展的方式去设计。
下面贴出我设计的 SocketUtil :
// ----------------- 接口 ----------------------
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 java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
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,好像有点感觉,但是模模糊糊的,理解不完全更讲不出来,很希望得到高人指点。
最后,加上一些我自己的理解:
接口,抽象,具体实现;这三个玩意儿之间的关系其实就是:“程序员”、“架构师(或者组长)”和“项目经理”。
“项目经理”懂功能以及沟通,他就是个接口,外行或者说决策层的人想做个玩意儿或者功能,就要和他说,因为他知道这个功能在我的团队中能不能按要求完成;所以他就是接口。外面拿到这个接口之后,接口就要到下面去找这个具体的实现,也就是“程序员”。
“程序员”完成具体的工作,不管你是想在展示层(UI)上加一句话,还是加个服务器端的什么功能,都得是程序员一个字母一个符号的用手敲出来(包括粘贴复制等等)。所以他们就是具体的实现类。他们之间的关系是项目经理知道的,项目经理说能做的,他们就知道就能做(不会也得会,要不就没饭吃),而且项目经理只负责告诉他该做什么,具体怎么做随便,只要按要求完成就可以。
那么“架构师”是干什么的?架构师就是抽象类,抽象类集成接口并且实现或者创建一些 具体实现(类) 都用的公共(或者保护)方法。就好像架构师负责整个系统的架构设计和框架的搭建以及各种基类(部分工具类)的封装。
接口,抽象,具体实现,在我们的生活中到处都是,只是好公司严格规范,土豪公司各种乱七八糟。
我写的这么卖力,仅仅事项学习交流,希望各位能留下宝贵意见,在此谢过看到这写文字每一位
接口 架构师 面向接口编程 NIO socket --------------------编程问答-------------------- 推荐一下!! --------------------编程问答-------------------- 这么多年编程,我好像没有见过那个语言的API,或者3rd的库有Socket Utility这样的接口啊。。。 。。。
楼主你想多了。。。 --------------------编程问答-------------------- 而且一看你的HttpUtil extends SocketUtil我就想吐血。。。
你误解了很多东西,
HTTP确实是TCP实现的,但是我从来没有见过任何一个HttpConnection的类是继承自TcpConnection的。
--------------------编程问答-------------------- 这怎么回复某个楼层? --------------------编程问答-------------------- Util : 程序中一般译为:工具的意思
你写个接口,也用这个名称,不太适合;
一般接口:interface,我们都会以:大写的"I"开头;
如:
public interface IDisposable
{
void Dispose();
}
public class A Implements IDiposable
{
}
public class Main
{
public static void Main(String[] args)
{
IDisposable idObj = ....;///这里一看I开头就知道是接口;Util别以为是工具类;
}
} --------------------编程问答-------------------- 回复 healer_kx :
我是想尽可能的保留通用和可扩展性。
能够给个粗略的设计或者描述? --------------------编程问答-------------------- 很好啊 很有用 --------------------编程问答-------------------- 感谢 linjf520 :
有个疑问,我看有的开源产品接口就是一个名字,而"I"是用在它的实现类的名字上,好像Spring就是这样的。 --------------------编程问答-------------------- 在面向对象中;
抽象这东西;
在C++中;可能就抽象类;
在C#、Java中,除了抽象类,还有接口;
而接口是纯抽象的一个东西;
什么东西应该抽为抽象;
就是按需求,或是现实分类时,把事物的共通点抽象出来,而得来的分类名称;
如:人:女人、男人,婴儿,老人,残疾人;等;
纯抽象:人,interface
后台的,什么什么人,这些都是再次抽象分类;abstract,当然,你也可以定为interface也行;
他们都是extends 人或是implement 人这个纯抽象接口;
而实际的实现,可能就是某个存在的人;
抽象得适不适合,就是看你对事物的分类理解,或是生活的理解; --------------------编程问答-------------------- 上面有打错字,重发,CSDN不可以编辑自己发的内容。。。唉。。。
====
在面向对象中;
抽象这东西;
在C++中;可能就抽象类;
在C#、Java中,除了抽象类,还有接口;
而接口是纯抽象的一个东西;
什么东西应该抽为抽象;
就是按需求,或是现实分类时,把事物的共通点抽象出来,而得来的分类名称;
如:人:女人、男人,婴儿,老人,残疾人;等;
纯抽象:人,interface
后面的,什么女、男,婴儿,老人,这些都是再次抽象分类;abstract,当然,你也可以定为interface也行;
他们都是extends 人或是implement 人这个纯抽象接口;
而实际的实现(没有abstract的class),可能就是某个存在的人;
抽象得适不适合,就是看你对事物的分类理解,或是生活的理解; --------------------编程问答-------------------- 感谢 linjf520 :
个人觉得,抽象是为了隔离、方便扩展、便于理解以及提高编码速度;我现在最想搞定的是方便扩展,怎么能让它在将来尽量少改动或者不改动,只用添加和替换的方式修改添加改变功能? --------------------编程问答--------------------
按实际的需求,分类去抽象呗;
如果到后面发现,有分类不合理,及时改掉;
就不影响后续扩展; --------------------编程问答--------------------
如果按照:
SocketUtil可以用于普通的长连接以及HTTP请求;主要是设计HTTP的接口或者抽象类,但是一定要给普通长连接留下开发余地,尽量满足开闭原则。
能不能粗略的设计一下? --------------------编程问答--------------------
Util : 程序中一般译为:工具的意思
你写个接口,也用这个名称,不太适合;
一般接口:interface,我们都会以:大写的"I"开头;
如:
public interface IDisposable
{
void Dispose();
}
public class A Implements IDiposable
{
}
public class Main
{
public static void Main(String[] args)
{
IDisposable idObj = ....;///这里一看I开头就知道是接口;Util别以为是工具类;
}
}
给个方向吧 --------------------编程问答-------------------- public interface IConnection
{
... receive(ref Byte[] bytes,...);//最好还有异步的receive
... send(Byte[] bytes);//最好还有异步的send
... connect();//最好也有:异步的connect
... disconect();
}
完了,就这么多;
至于你用于Http或是其它作用的普通的长连接,再自己去实现吧;
public interface IGameConnection extends IConnection
{
..扩展
}
public interface IHttpConnection extends IConnection
{
..扩展
} --------------------编程问答-------------------- 什么东西哈 没看完还是回回 --------------------编程问答--------------------
HTTP确实是TCP实现的,但是我从来没有见过任何一个HttpConnection的类是继承自TcpConnection的。
不太理解你表达的意思,你是说HttpConnection可以多种方式实现,不同环境用不同实现,直接继承TcpConnection写个实现没有实际使用价值? --------------------编程问答--------------------
HTTP确实是TCP实现的,但是我从来没有见过任何一个HttpConnection的类是继承自TcpConnection的。
不太理解你表达的意思,你是说HttpConnection可以多种方式实现,不同环境用不同实现,直接继承TcpConnection写个实现没有实际使用价值?
我也一直在琢磨这句话,如果按照“SocketUtil可以用于普通的长连接以及HTTP请求;主要是设计HTTP的接口或者抽象类,但是一定要给普通长连接留下开发余地,尽量满足开闭原则”,好像能想到的就类似linjf520的方法
public interface IConnection
{
... receive(ref Byte[] bytes,...);//最好还有异步的receive
... send(Byte[] bytes);//最好还有异步的send
... connect();//最好也有:异步的connect
... disconect();
}
完了,就这么多;
至于你用于Http或是其它作用的普通的长连接,再自己去实现吧;
public interface IGameConnection extends IConnection
{
..扩展
}
public interface IHttpConnection extends IConnection
{
..扩展
}
是不是我的那个要求或者说愿望就是个错误? --------------------编程问答-------------------- 是不是我的那个要求或者说愿望就是个错误?
SocketUtil可以用于普通的长连接以及HTTP请求;主要是设计HTTP的接口或者抽象类,但是一定要给普通长连接留下开发余地,尽量满足开闭原则 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 长连接,短连接,这些是你内部的机制处理;具体实现。 --------------------编程问答--------------------
长连接,短连接,这些是你内部的机制处理;具体实现。
非常谢谢你,我先按照你的方法试着写一下 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 学习一下撒 --------------------编程问答-------------------- 参考LSP,然后再带人你的class,看看是否还OK~ --------------------编程问答--------------------
参考LSP,然后再带人你的class,看看是否还OK~
没看懂啊… --------------------编程问答--------------------
没看懂 --------------------编程问答-------------------- 进来看一下......... --------------------编程问答-------------------- 进来看一下......... --------------------编程问答--------------------
进来看一下.........
谢谢,如果能提些建议就更好了 --------------------编程问答-------------------- 楼主说的对, --------------------编程问答-------------------- 必须顶啊 虽然不知道什么 --------------------编程问答-------------------- 设计的确是精巧的活,差之毫厘,失之千里。我的意思是说看起来相似的设计,可能因为一点点不同,产生的结果会相差很大,比如 有些人 喜欢用EventListener模式,但是所做的设计是错的,最终根本没有解耦,反倒耦合更大。 --------------------编程问答-------------------- 支持呢!~~~ --------------------编程问答-------------------- 勇敢实践才有收获。 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- learning --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- --------------------编程问答-------------------- 看看是什么~ --------------------编程问答-------------------- 不明觉厉 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 感谢楼主分享,小白学习中…… --------------------编程问答-------------------- 学习学习,我也不是很懂啊。。。 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 楼主辛苦,我是新手,想跟着你们大神学点东西 --------------------编程问答-------------------- 学习了哈哈,good --------------------编程问答--------------------
还是顶一个吧。。。
--------------------编程问答-------------------- 学习了 --------------------编程问答-------------------- 看看是什么~ --------------------编程问答-------------------- 推荐一下!! --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 看看看看看看看看 --------------------编程问答-------------------- bu cuo yo --------------------编程问答-------------------- 能练习本身就是一个进步.很好.以后你会做的更好,比现在更有体悟.
--------------------编程问答-------------------- 新人来学习了 --------------------编程问答-------------------- 如果把http压缩再考虑进去,就更好了 --------------------编程问答-------------------- 支持楼主 --------------------编程问答-------------------- 长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。
而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。
我自己学习一下 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 路过,学习了 --------------------编程问答-------------------- 过来看看 本人菜鸟一枚 --------------------编程问答-------------------- interface是大家做事的规范(规定了大家要做什么,动作是什么),abstract class是做事的模板(大家可以依据模板实现自己特殊的要求)。粘合剂就是多态。 --------------------编程问答-------------------- 好 支持 顶 正好需要socket方面的资料
补充:Java , Java SE