I have implemented state pattern for my socket library in Java. I simplified code to reduce size and increase readability just to demonstrate the problem. I don't know how to encapsulate using of Socket class by states classes. I've written comments to better understanding the problem. So, there is an example code:
package com.test;
enum ConnectionAttemptResult {
ConnectionAttemptStarted,
AlreadyInProgress,
AlreadyConnected,
UnableToCreateSocket,
UnableToConnectSocket,
UnableToCreateReadEvent
}
class SocketAddress {
static SocketAddress LocalhostPort(int port) {
// Code removed.
return new SocketAddress();
}
}
class Socket {
private State currentState;
Socket() {
this.currentState = new NotActiveState(this);
}
public ConnectionAttemptResult Connect(SocketAddress remoteAddress) {
return this.currentState.Connect(remoteAddress);
}
// Socket class is external and will be used by user.
// So further methods must be private because they are internal.
// Calling these methods by a user may broke class functionality.
// But I can't make them private because then states couldn't access them.
public void SwitchState(State newState) {
this.currentState = newState;
}
// I removed a lot of code of this class to simplify the code.
public boolean CreateSocket() {
// Code removed.
return true;
}
public boolean ConnectSocket(SocketAddress remoteAddress) {
// Code removed.
return true;
}
public boolean CreateReadEvent() {
// Code removed.
return true;
}
}
abstract class State {
protected Socket socket;
State(Socket socket) {
this.socket = socket;
}
public abstract ConnectionAttemptResult Connect(SocketAddress remoteAddress);
}
class NotActiveState extends State {
NotActiveState(Socket socket) {
super(socket);
}
@Override
public ConnectionAttemptResult Connect(SocketAddress remoteAddress) {
if (!socket.CreateSocket())
return ConnectionAttemptResult.UnableToCreateSocket;
if (!socket.ConnectSocket(remoteAddress))
return ConnectionAttemptResult.UnableToConnectSocket;
if (!socket.CreateReadEvent())
return ConnectionAttemptResult.UnableToCreateReadEvent;
socket.SwitchState(new ConnectingState(socket));
return ConnectionAttemptResult.ConnectionAttemptStarted;
}
}
class ConnectingState extends State {
ConnectingState(Socket socket) {
super(socket);
}
@Override
public ConnectionAttemptResult Connect(SocketAddress remoteAddress) {
return ConnectionAttemptResult.AlreadyInProgress;
}
}
class ConnectedState extends State {
ConnectedState(Socket socket) {
super(socket);
}
@Override
public ConnectionAttemptResult Connect(SocketAddress remoteAddress) {
return ConnectionAttemptResult.AlreadyConnected;
}
}
class Main {
public static void main(String[] args) {
Socket socket = new Socket();
socket.Connect(SocketAddress.LocalhostPort(9898));
// But I also can call internal methods and break the class functionality, because now they are public.
socket.CreateSocket();
socket.CreateReadEvent();
}
}
Where is my mistake? How usually developers implement this pattern saving encapsulation? Hope for your help! Thanks in advance!
Aucun commentaire:
Enregistrer un commentaire