文章目录
前言
前面构建整个架构的时候没有设定Player的抽象接口,玩家的指令解析后调用的方法也不是Player中的函数,这对后续的维护和扩展非常不友好。
由于player由Room类中的players存放,因此所有IPlayer均不作为Spring的Component使用
一、重构pojo接口及实现类
1.抽象底层IPlayer接口
public interface IPlayer extends Runnable {
public void move(Instruct instruct);
public void moveOut(Instruct instruct);
}
每个Player对象都实现了Runnable接口用于需要长时间调用的函数(如跑动等)的线程的创建。
INormalPlayer
public interface INormalPlayer extends IPlayer {
}
IPolice
//警察接口
public interface IPolice extends IPlayer {
//射击
public void shut(Instruct instruct);
//抓捕
public void arrest(Instruct instruct);
}
Thief
//小偷接口
public interface IThief extends IPlayer {
//偷窃
public void steal(Instruct instruct);
}
2.实现类
public class PlayerPeople implements IPlayer {
private double x;
private double y;
private int uid;
private int token;
private boolean move = false;
private double angle;
private float speed = 30;
private long time;
public PlayerPeople(double x, double y, int uid, int token, boolean move, double angle, float speed) {
this.x = x;
this.y = y;
this.uid = uid;
this.token = token;
this.move = move;
this.angle = angle;
this.speed = speed;
}
@Override
public void move(Instruct instruct) {
if (this.move != true) {
this.move = true;
//新建一个线程
new Thread(this).start();//后续重构改为线程池...
}else {
//跑动线程已存在不需要再创建
}
this.time = System.currentTimeMillis();//由于前后端时间差过大,这里先设为当前时间
this.angle = (double) instruct.getObj();
}
@Override
public void moveOut(Instruct instruct) {
this.move = false;
}
@Override
public void run() {
//这里执行需要长期计算的指令逻辑(如跑动等)
//("跑动线程")
long timeDiffer = 0;
while(this.move){
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized ((Long)time) {
timeDiffer = System.currentTimeMillis() - time;
time = System.currentTimeMillis();
this.x = (this.x + (timeDiffer * this.speed * 0.1F * Math.sin(Math.PI / 180 * this.angle)));
this.y = (this.y - (timeDiffer * this.speed * 0.1F * Math.cos(Math.PI / 180 * this.angle)));
}
}
}
}
这里仅给出PlayerPeople的实现类,其他的实现类暂时都继承于该类并实现其对应的接口
例如
public class Police extends PlayerPeople implements IPolice {
public Police(double x, double y, int uid, int token, boolean move, double angle, float speed) {
super(x, y, uid, token, move, angle, speed);
}
@Override
public void shut(Instruct instruct) {
}
@Override
public void arrest(Instruct instruct) {
}
}
二、简单工厂模式创建Player
1.创建Player枚举类型
public enum Players {
NormalPlayer(30),
Police(60),
Thief(100);
//选择中的几率(前减后)
private int probability;
private static Random random = new Random();
Players(int probability) {
this.probability = probability;
}
public static Players getRandomPlayer() {
int r = random.nextInt(99)+1;
for (Players p : values()){
if (p.probability > r){
return p;
}
}
//如果失败了则随机返回
return values()[random.nextInt(values().length)];
}
}
这里玩家身份随机生成,逻辑如代码所示。
2.创建PlayerFactory工厂类
//简单工厂创建Player
public class PlayerFactory {
public static IPlayer createPlayer(Class<? extends IPlayer> clazz)
throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
return (IPlayer) clazz.getDeclaredConstructor().newInstance();
}
}
传入的是一个Class类对象
3.在MsgManage中调用工厂创建
public static void join(Instruct instruct){
//在Room里面加入...
try {
Class clazz = Class.forName(Players.getRandomPlayer().toString());
Room.players.put(instruct.getUid() + "" , PlayerFactory.createPlayer(clazz));
}catch (Exception e){
System.out.println("随机生成Player异常");
}
}
总结
1.使用枚举类型保存所有的玩家身份类型,并通过静态方法随机生成一个玩家身份。
2.使用工厂模式生成单一职责的接口继承类,符合代码开闭原则,对后续玩家身份的扩展有很大的进步。