java基础巩固-宇宙第一AiYWM:为了维持生计,手写RPC01~Version01整起

发布时间:2023-08-24 08:00

历史背景:故事起源于,敏小言和他老公小胡开了一家超市。这个超市里面由很多小柜子组成,这些个小柜子是用来存小胡他们要卖的东西。买东西时别人在网上选定几号柜台后提交订单,然后敏小言通知小胡把东西送到指定的小柜子中,由买家自己来取。

主要的逻辑如下Readme.txt中:
\"java基础巩固-宇宙第一AiYWM:为了维持生计,手写RPC01~Version01整起_第1张图片\"

这天,正巧敏小言有事回娘家去了,没在店里。但是小胡只会送东西其他的一概不会。

第一天:有个客人买了个熊猫型抱枕,小胡连忙给敏小言打电话。
小胡:老婆,有人买了个熊猫型抱枕
敏:哎呀,咱们抱枕柜子还没整理好,只有两个用来区分的标识,id和clothesColor。你把顾客要的抱枕对应的id告诉我。

  • 小胡心想(哎呀,这不是,我媳妇变成服务器端了,我现在作为客户端现在把id给她,她查一下,这个id对应的Pillow,然后把这个Pilliow再传送给我,我再放到柜子里等顾客去取就行。作为一个程序员,这个过程咋实现呢???)。首先,作为面向对象的选手,这个Pillow不给他搞成一个对象能行?
    \"java基础巩固-宇宙第一AiYWM:为了维持生计,手写RPC01~Version01整起_第2张图片\"
/**
 * Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
 */
package entity;

import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 客户端敏小言与服务端小胡都已知的实体,客户端需要得到这个pojo对象数据,服务端需要操作这个对象,咱们这种情境下就是服务器需要去按照客户端提供的信息查询一下这个对象,再把查找到对象返还给客户端
 * 
 * 比如,本机上另外一个类想拿到我这个Pilliow对象去使用,拿到给他这不就是本地通信或者传输嘛 ,但是,如果另外一台机器上的一个东西想拿到我这个Pilliow对象去使用,拿给他这不就是远程通信嘛
 * @author HuHongBo
 * @version 2022年5月5日
 */
//@Builder
//@Data
//@NoArgsConstructor
//@AllArgsConstructor
public class Pilliow implements Serializable {
	private static final long serialVersionUID = 1L;
	private Integer id;
	private String clothesColor;

	public Pilliow(Integer id, String clothesColor) {
		super();
		this.id = id;
		this.clothesColor = clothesColor;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getClothesColor() {
		return clothesColor;
	}

	public void setClothesColor(String clothesColor) {
		this.clothesColor = clothesColor;
	}

	@Override
	public String toString() {
		return \"Pilliow [id=\" + id + \", clothesColor=\" + clothesColor + \"]\";
	}

}

然后,小胡把id给敏小言发过去时,自己就开始阻塞等待:
什么时候把Pillow发送来呢?
什么时候把Pillow发送来呢?什么时候把Pillow发送来呢?
什么时候把Pillow发送来呢?什么时候把Pillow发送来呢?什么时候把Pillow发送来呢?

然后敏小言那边作为服务端,调用服务(方法)用id查找到那个Pillow后,就开始把这个Pillow给小胡发过去。
然后小胡收到了Pillow后,就去把Pillow塞到柜子里等顾客去取就行了。
其中有些偷懒细节,看注释:
\"java基础巩固-宇宙第一AiYWM:为了维持生计,手写RPC01~Version01整起_第3张图片\"

/**
 * Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
 */
package client;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;

import entity.Pilliow;

/**
 * 客户端是需要把id=221这个id值写给服务器端,这样服务器端才能帮咱们按照这个id去找到这个Pillow呀
 * 	由于网络上只能传输二进制,所以咱们得把这个id值,也就是221转换成为二进制
 * 	Java中可以用这三句代码,就会自动帮咱们把id这个221值转为221对应的二进制
 * 		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
		dataOutputStream.writeInt(221);
 * 
 * @author HuHongBo
 * @version 2022年5月12日
 */
public class Client {
	public static void main(String[] args) throws Exception {
		Socket socket = new Socket(\"127.0.0.1\", 2221);
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
		dataOutputStream.writeInt(221);
		
		/**
		 * 把表示221这个id值的二进制转为真正的int字节数组,再通过.write方法把这个字节数组给写出去,然后这个字节数组,也就是id=221才能到服务器端
		 */
		socket.getOutputStream().write(byteArrayOutputStream.toByteArray());
		socket.getOutputStream().flush();
		
		/**
		 * 他服务器那边偷了个懒嘛,虽然说后面有更高级的方式可以把Pillow些过来给我,但是现在他就是在偷懒,只把Pillow的俩属性写过来了
		 * 那我客户端DataInputStream就在这里阻塞着,等着读,服务器端发来的Pillow对象
		 */
		DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
		/**
		 * 废话,既然你是偷懒,传俩属性过来,我这边也是把id和clothesColor分别读进来就行
		 */
		int id = dataInputStream.readInt();
		String clothesColor = dataInputStream.readUTF();
		Pilliow pillow = new Pilliow(id, clothesColor);
		
		System.out.println(pillow);
		
		dataOutputStream.close();
		socket.close();
	}
}

\"java基础巩固-宇宙第一AiYWM:为了维持生计,手写RPC01~Version01整起_第4张图片\"

/**
 * Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
 */
package server;

import entity.Pilliow;

/**
 * 定义客户端需要调用,服务端需要提供的服务接口
 * getUserByUserId()这个方法或者说这个方法所在的类,就是咱们的一个服务呀,供别人调用的
		 * 
		 * 那我调用服务的思路就是:我想查id为221的那个人,我客户端是不是得先把id=221这个id写给服务端
		 * 然后服务端查到这个人后,转成二进制给我客户端再返回回来(写回来)
		 * 我这边收到之后再进行解析
 * @author HuHongBo
 * @version 2022年5月5日
 */
public interface PilliowService {
	/**
	 * 客户端通过这个接口调用服务端的实现类
	 * @param id
	 * @return
	 * @author HuHongBo
	 */
    Pilliow getPilliowByPilliowId(Integer id);
}

/**
 * Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
 */
package server;
import entity.Pilliow;

/**
 * getPilliowByPilliowId()这个方法或者说这个方法所在的类,就是咱们的一个服务呀,供别人调用的
		 * 
		 * 那我调用服务的思路就是:我想查id为221的那个人,我客户端是不是得先把id=221这个id写给服务端
		 * 然后服务端查到这个人后,转成二进制给我客户端再返回回来(写回来)
		 * 我这边收到之后再进行解析
 * @author HuHongBo
 * @version 2022年5月5日
 */
public class PilliowServiceImpl implements PilliowService{

	@Override
	public Pilliow getPilliowByPilliowId(Integer id) {
		/**
		 * 当然,实体类中的这些成员变量的值一般实际中都是从数据库中或者说缓存中查出来的
		 */
		return new Pilliow(id, \"black 卫衣\");
	}

}

/**
 * Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
 */
package server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import entity.Pilliow;


/**
 * 
 * getPilliowByPilliowId()这个方法或者说这个方法所在的类,就是咱们的一个服务呀,供别人调用的
* 
* 那我调用服务的思路就是:我想查id为221的那个人,我客户端是不是得先把id=221这个id写给服务端
* 然后服务端查到这个人后,转成二进制给我客户端再返回回来(写回来)
* 我这边收到之后再进行解析
 * 
 * @author HuHongBo
 * @version 2022年5月12日
 */
public class Server {
	private static boolean flag = true;
	
	public static void main(String[] args) throws Exception{
		/**
		 * 别人可以通过这个端口来远程连接我这个Server,也就是服务
		 */
		ServerSocket serverSocket = new ServerSocket(2221);
		while(flag){
			/**
			 * 通过accept接收一个客户端连接
			 */
			Socket socket = serverSocket.accept();
			/**
			 * 对客户端的连接进行处理
			 */
			process(socket);
			socket.close();
		}
	}

	/**
	 * 
	 * @param socket
	 * @throws Exception
	 * @author HuHongBo
	 */
	private static void process(Socket socket) throws Exception {
		/**
		 * 拿到输入流
		 */
		InputStream inputStream = socket.getInputStream();
		OutputStream outputStream = socket.getOutputStream();
		DataInputStream dataInputStream = new DataInputStream(inputStream);
		DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
		
		/**
		 * 从输入流中解析出,谁把这个id传给我的,我把这个id读出来
		 * 	刚刚咱们在客户端不是发过来一个id为221的整数对应的二进制,然后还把这个二进制转为字节数组了嘛
		 * 下来咱们通过readInt()把代表221的字节数组都进来,转换成为一个int类型的id
		 */
		int id = dataInputStream.readInt();
		PilliowServiceImpl serviceImpl = new PilliowServiceImpl();
		/**
		 * getPilliowByUPilliowId()这个方法或者说这个方法所在的类,就是咱们的一个服务呀,供别人调用的
		 * 
		 * 那我调用服务的思路就是:我想查id为221的那个人,我客户端是不是得先把id=221这个id写给服务端
		 * 然后服务端查到这个人后,转成二进制给我客户端再返回回来(写回来)
		 * 我这边收到之后再进行解析,我服务器端,拿到了这个id值然后就能找到一个对应的Pilliow嘛
		 */
		Pilliow pilliow = serviceImpl.getPilliowByPilliowId(id);
		/**
		 * 把得到的pilliow写出去
		 * 	其实这里我偷了个懒,因为我知道你Pilliow就俩属性id和clothesColor这俩属性,我把这俩属性写给你也就相当于把这个Pilliow对象写给你了嘛
		 */
		dataOutputStream.writeInt(pilliow.getId());
		dataOutputStream.writeUTF(pilliow.getClothesColor());
		dataOutputStream.flush();
		
	}
}

那这个Version01有什么缺陷呢?

  • 这个最原始的方式非常的麻烦,缺点多多,如下:
    • 如果我这个Pilliow里面属性很多,你不得该一大片。或者说,我想把id或者衣服颜色改改,你就要改很多部分,说明程序耦合的太死。
    • 而且,如果除了Pilliow对象后,如果还有其他对象,我怎么办?一个对象一个对象来搞?
      • 而且这些对象在不断演进,对象的属性在不断的增减,程序得跟着不断的动

所以Version02应运而生
…未完待续

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号