【发布时间】:2011-01-10 17:18:43
【问题描述】:
我使用单例和观察者模式编写了一个带有 Swing 接口的简单服务器 - 客户端程序。每个客户端都连接到服务器并可以发送消息。服务器将它收到的消息转发给其余的客户端。客户端使用允许他们随时连接和断开服务器的 GUI。 该程序运行良好,因为我尝试在所有处理可能发生的异常的地方捕获。但是,如果您使用它,您将在控制台中看到一百万个异常。这可能是因为糟糕的设计,但我已经尽力做一个干净的代码。 所以问题是:
谁能给我一些提示和建议,告诉我如何重构代码以使其更正确和更干净(尤其是在断开客户端与服务器的连接时)?
CustomServer 类中有一个 main 方法来启动服务器和一个
控制器中的 main 方法来启动客户端(使用 GUI)。
感谢您的热心帮助!
代码如下:
自定义服务器类
package model;
import java.io.*;
import java.net.*;
import controller.Controller;
public class CustomServer extends Thread{
private ServerSocket ss = null;;
public CustomServer() throws Exception {
ss = new ServerSocket(4444);
this.start();
}
@Override
public void run(){
while (true){
try {
Socket connSoc = ss.accept();
new Connect(connSoc);
} catch (IOException e) {
e.printStackTrace();
try{
ss.close();
}catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
private class Connect extends Thread{
ObjectOutputStream out;
ObjectInputStream in;
public Connect(Socket connSoc) {
final IOController server = IOController.getInstance();
try {
out = new ObjectOutputStream(connSoc.getOutputStream());
in = new ObjectInputStream(connSoc.getInputStream());
server.add(in, out);
}catch (Exception e) {
e.printStackTrace();
try{
connSoc.close();
}catch (Exception ex) {
e.printStackTrace();
}
}
this.start();
}
}
public static void main(String[] args) throws Exception{
new CustomServer();
}
}
自定义客户端类
package model;
import java.io.*;
import java.net.*;
import java.util.*;
public class CustomClient extends Observable{
private Socket connSocket;
private ObjectOutputStream out;
private ObjectInputStream in;
private boolean isOn = true;
private Thread receiver;
public CustomClient() throws Exception{
System.out.println("inside CClient");
Socket soc = new Socket();
soc.connect(new InetSocketAddress(InetAddress.getLocalHost(), 4444));
out = new ObjectOutputStream(soc.getOutputStream());
in = new ObjectInputStream(soc.getInputStream());
}
public void transmit(Object obj){
System.out.println("CClient - transitmin - start");
try {
out.writeObject(obj);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("CClient - transitmin - end");
}
public void reveive(){
System.out.println("CClient - recieve - start");
receiver = new Thread(new Runnable() {
@Override
public void run() {
while (isOn){
Object obj = null;
try {
obj = in.readObject();
setChanged();
} catch (Exception ex){
ex.printStackTrace();
}
if (hasChanged()){
notifyObservers(obj);
}
}
}
});
receiver.start();
System.out.println("CClient - recieve - end");
}
public void closeConnection(){
try{
in.close();
} catch (Exception e) {
System.err.println("CAUGHT");
e.printStackTrace();
}
try{
out.close();
} catch (Exception e) {
System.err.println("CAUGHT");
e.printStackTrace();
}
finally {
try {
isOn = false;
in = null;
out = null;
connSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
connSocket = null;
}
}
public Socket getSocket(){
return connSocket;
}
}
IOController 类
package model;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
public class IOController{
ArrayList<ObjectInputStream> ins = new ArrayList<ObjectInputStream>();
ArrayList<ObjectOutputStream> outs = new ArrayList<ObjectOutputStream>();
private static IOController instance = new IOController();
private IOController() {
}
public static IOController getInstance(){
return instance;
}
public void add(final ObjectInputStream in, final ObjectOutputStream out){
ins.add(in);
outs.add(out);
new Connect(in);
}
private class Connect extends Thread{
ObjectInputStream in;
public Connect(ObjectInputStream in) {
this.in = in;
this.start();
}
@Override
public void run() {
boolean isOn = true;
ArrayList<ObjectOutputStream> toBeRemoved = new ArrayList<ObjectOutputStream>();
while(isOn){
try {
Object obj = in.readObject();
for (ObjectOutputStream out : outs){
try {
out.writeObject(obj);
out.flush();
}catch (Exception ex){
toBeRemoved.add(out);
ex.printStackTrace();
}
}
for (ObjectOutputStream oos : toBeRemoved){
outs.remove(oos);
}
}catch (Exception ex){
ins.remove(in);
isOn = false;
in = null;
ex.printStackTrace();
}
}
}
}
}
控制器类
package controller;
import java.awt.*;
import view.GUI;
import model.CustomClient;
public class Controller {
private GUI gui;
private CustomClient client;
public Controller() {
gui = new GUI();
gui.addConnectButtonActionListener(new ConnectButtonActionListener());
gui.addTextFieldKeyListner(new TextFieldKeyListener());
gui.addDisconnectButtonActionListener(new DisconnectButtonActionListener());
gui.addCustomWindowListener(new GuiWindowListener());
}
private class DisconnectButtonActionListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
client.closeConnection();
client = null;
gui.getDisconnectButton().setEnabled(false);
gui.getConnectButton().setEnabled(true);
}
}
private class ConnectButtonActionListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
try {
client = new CustomClient();
client.addObserver(gui);
client.reveive();
gui.getConnectButton().setEnabled(false);
gui.getDisconnectButton().setEnabled(true);
}catch (Exception ex) {
ex.printStackTrace();
}
}
}
private class TextFieldKeyListener extends KeyAdapter{
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode()==KeyEvent.VK_ENTER){
String msg = gui.getTextField().getText();
gui.getTextField().setText("");
if (client != null){
client.transmit(msg);
}
}
}
}
private class GuiWindowListener extends WindowAdapter{
@Override
public void windowClosing(WindowEvent e) {
try{
if (client != null){
client.closeConnection();
client = null;
}
}catch (Exception e2) {
}
System.out.println("closed");
}
}
public static void main(String[] args) {
new Controller();
}
}
和 GUI 类
package view;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class GUI extends JFrame implements Observer{
private JTextField textField;
private JTextArea displayArea;
private JButton connectButton;
private JButton disconnectButton;
public GUI() {
init();
setDefaultCloseOperation(EXIT_ON_CLOSE);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
pack();
setVisible(true);
textField.requestFocusInWindow();
}
});
}
public void addConnectButtonActionListener(ActionListener al){
connectButton.addActionListener(al);
}
public void addDisconnectButtonActionListener(ActionListener al){
disconnectButton.addActionListener(al);
}
public void addTextFieldKeyListner(KeyListener kl){
textField.addKeyListener(kl);
}
public void addCustomWindowListener(WindowListener guiWindowListener) {
addWindowListener(guiWindowListener);
}
public void appendText(String text){
displayArea.append("\n"+ text);
}
private void init() {
JPanel panel = new JPanel();
JPanel southPanel = new JPanel();
JPanel northPanel = new JPanel();
connectButton = new JButton("connect");
connectButton.setFocusable(false);
disconnectButton = new JButton("disconnect");
disconnectButton.setFocusable(false);
textField = new JTextField(20);
displayArea = new JTextArea();
displayArea.setEditable(false);
displayArea.setPreferredSize(new Dimension(300,250));
panel.setLayout(new BorderLayout());
southPanel.setLayout(new FlowLayout());
northPanel.setLayout(new FlowLayout());
northPanel.add(displayArea);
southPanel.add(connectButton);
southPanel.add(disconnectButton);
panel.add(textField,BorderLayout.CENTER);
panel.add(southPanel, BorderLayout.SOUTH);
panel.add(northPanel, BorderLayout.NORTH);
this.getContentPane().add(panel);
disconnectButton.setEnabled(false);
System.out.println(textField.hasFocus());
}
public JTextField getTextField() {
return textField;
}
public void setTextField(JTextField textField) {
this.textField = textField;
}
public JTextArea getDisplayArea() {
return displayArea;
}
public void setDisplayArea(JTextArea displayArea) {
this.displayArea = displayArea;
}
public JButton getConnectButton() {
return connectButton;
}
public void setConnectButton(JButton connectButton) {
this.connectButton = connectButton;
}
public JButton getDisconnectButton() {
return disconnectButton;
}
public void setDisconnectButton(JButton disconnectButton) {
this.disconnectButton = disconnectButton;
}
@Override
public void update(Observable observable, Object object) {
displayArea.append("\n"+(String)object);
}
}
【问题讨论】:
-
嗯。有很多代码希望人们阅读、使用、建议改进... 不相关的旁注:有一个“refactor-my-code”标签?这让我哭了。
-
我猜你是对的,这是一个远射。但在我的辩护中,代码似乎更大,实际上是因为我使用 MVC 和观察者模式!
-
我们可以在 codereview.stackexchange.com 尝试,但您需要声明焦点,甚至将其拆分为多个问题,才能真正期待良好的反馈。
标签: java multithreading sockets refactoring