一)接口简介
Java接口是一系列方法的声明,是一些方法特征的集合,同时也是一种比抽象类要高级的规范,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。
两个类中的两个类似的功能,调用他们的类动态的决定一种实现,那他们提供一个抽象父类,子类分别实现父类所定义的方法。
问题的出现:Java是一种单继承的语言,一般情况下,哪个具体类可能已经有了一个超类,解决是给它的父类加父类,或者给它父类的父类加父类,直到移动到类等级结构的最顶端。这样一来,对一个具体类的可插入性的设计,就变成了对整个等级结构中所有类的修改。
在一个等级结构中的任何一个类都可以实现一个接口,这个接口会影响到此类的所有子类,但不会影响到此类的任何超类。此类将不得不实现这个接口所规定的方法,而其子类可以从此类自动继承这些方法,当然也可以选择置换掉所有的这些方法,或者其中的某一些方法,这时候,这些子类具有了可插入性(并且可以用这个接口类型装载,传递实现了他的所有子类)。
我们关心的不是那一个具体的类,而是这个类是否实现了我们需要的接口。
接口提供了关联以及方法调用上的可插入性,软件系统的规模越大,生命周期越长,接口使得软件系统的灵活性和可扩展性,可插入性方面得到保证。
Java接口(以及抽象类)一般用来作为一个类型的等级结构的起点。
如果一个类已经有了一个主要的超类型,那么通过实现一个接口,这个类可以拥有另一个次要的超类型,这种次要的超类型叫做混合类型。
二)实战应用
1)简单规范实例
1】实体接口
package com.xiu.interfaces;
import java.io.Serializable;
/**
*实体接口
*
* @author xiu
* @version 2017年8月3日 上午11:00:05
*/
public interface IEntity<K extends Serializable> {
/**
* 获取主键
* @return
*/
K getId();
}
2】实现
@Entity(tableName = "backpack", comment = "背包")
public class BackpackEntity implements IEntity<Long> {
@Id
@Column(name = "id", comment = "玩家id")
private long id;
@Column(name = "grid_content", length = 20000, comment = "背包格子")
private List<BackpackGrid> grids = new ArrayList<>();
@Override
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<BackpackGrid> getGrids() {
return grids;
}
public void setGrids(List<BackpackGrid> grids) {
this.grids = grids;
}
}
@Entity(tableName = "notice", comment = "公告表")
public class NoticeEntity implements IEntity<Integer>{
@Id
@Column(name = "id", comment = "公告编号")
private int id;
@Column(name = "notice_type", comment = "公告类型 1跑马灯,2活动公告,3登录公告")
private int noticeType;
@Column(name = "title", length = 1000 , comment = "标题")
private String title;
@Column(name = "content", length = 63001 , comment = "内容")
private String content;
@Column(name = "stime", comment = "公告展示开始时间(秒)")
private int stime;
@Column(name = "etime", comment = "公告展示结束时间(秒)")
private int etime;
@Column(name = "diffTime", comment = "播放时间间隔(以秒为单位)")
private int diffTime;
@Column(name = "level", comment = "数值越大,优先级越高")
private int level;
@Column(name = "status", comment = "公告状态(0正常,1删除)")
private StatusType status;
@Override
public Integer getId() {
return this.id;
}
2)消息推送模块实现
1】接口规范
主要规范方法:发送推送请求、单条、多条消息推送
package com.xiu.push;
import java.util.Collection;
/**
*
*
* @author xiu
* @version 2017年8月3日 上午11:29:24
*/
public interface IPush {
/**
* 发送推送请求
* @param dPushNotification
* @throws Exception
*/
void send(DPushNotification dPushNotification) throws Exception;
/**
* 单播推送
* @param role
* @param msgId
* @param args
* @throws Exception
*/
void unicastPush(Role role, int msgId, Object... args) throws Exception;
/**
* 单播推送
* @param role
* @param msg
* @param ticker
* @param title
* @throws Exception
*/
void unicastPush(Role role, String msg, String ticker, String title) throws Exception;
/**
* 列播推送
* @param roles
* @param msgId
* @param args
* @throws Exception
*/
void listcastPush(Collection<Role> roles, int msgId, Object...args) throws Exception;
}
Role为玩家实体类,DPushNotification为推送消息数据结构
package com.xiu.push;
/**
*推送消息数据结构
*
* @author xiu
* @version 2017年8月3日 上午11:30:16
*/
public class DPushNotification {
/**角色id*/
private long rid;
/***/
private long extendsionId;
/**消息内容*/
private String msgContext="";
/**推送时间*/
private int pushTime;
/**是否阅后即删*/
private boolean isRemove;
/**消息类型*/
private int type;
/**标题*/
private String title;
/**事件类型*/
private int eventId;
//对应getter、setter
}
2】接口实现
@Component
public class PushService implements IPush{
//TODO
}
3)Function/Manager接口
在实际开发中Function或者Manager都是具体的业务逻辑实现类,相当于MVC分层模式中的Controller,负责数据的验证分发等,或者执行特定的逻辑。
1】IFunction接口
package com.xiu.function;
import com.xiu.push.Role;
/**
*游戏逻辑接口
*
* @author xiu
* @version 2017年8月3日 上午11:49:59
*/
public interface IFunction {
/**
* 服务器启动时对游戏库的处理
*/
public void handleOnServerStart();
/**
* 服务器启动时对日志库的处理
*/
public void handleOnServerStartLog();
/**
* 在角色登陆的时候处理
* @param role
*/
public void handleOnRoleLogin(Role role);
/**
* 在角色下线的时候处理
* @param role
*/
public void handleOnRoleLogout(Role role);
/**
* 凌晨时候的处理
*/
public void handleOnNextDay() ;
/**
* 服务器准备关闭前调用
*/
public void handleOnServerShutdown();
}
该接口主要逻辑方法有五个:在服务器启动、关闭,角色登录、下线,跨天时执行
同理,战斗逻辑接口、道具逻辑接口也会有相关的规范设计。
2】FunctionAdapter逻辑索引
所有子类游戏逻辑只要继承基类或父类接口,就拥有父类接口的方法规范或者父类属性。
/**
*公用逻辑处理
*
* @author xiu
* @version 2017年8月3日 下午12:01:49
*/
public class FunctionAdapter implements IFunction {
public FunctionAdapter() {
FunctionManager.register(this);
}
@Override
public void handleOnServerStart() {
//default handle nothing
}
@Override
public void handleOnServerStartLog() {
//default handle nothing
}
@Override
public void handleOnRoleLogin(Role role) {
//default handle nothing
}
@Override
public void handleOnRoleLogout(Role role) {
//default handle nothing
}
@Override
public void handleOnNextDay() {
//default handle nothing
}
@Override
public void handleOnServerShutdown() {
// TODO Auto-generated method stub
}
}
观察上面发现多了一个构造方法FunctionAdapter(),这种用法很常见,也是Java多态特性的应用,只需要父类实现了该功能,子类只要继承于此并且重写这些方法就能拥有这些特性,而不需要单独去实现某些逻辑方法。
3】FunctionAdapter()的作用是注册继承于IFunction接口的所有子类到FunctionManager中,然后通过Funciton管理器统一处理规范方法。
package com.xiu.function;
import java.util.HashMap;
import java.util.Map;
import com.xiu.push.Role;
/**
*公用逻辑管理器
*
* @author xiu
* @version 2017年8月3日 下午1:52:52
*/
public class FunctionManager {
private static Map<Class<? extends IFunction>, IFunction> functionMap = new HashMap<Class<? extends IFunction>, IFunction>();
/**
* 把所有继承于IFunction接口的类注册到functionMap中,通过Funciton管理器统一管理这些子类逻辑
* @param function
*/
public static void register(IFunction function) {
if (functionMap.containsKey(function.getClass())) {
throw new RuntimeException("Duplicate function register "+function.getClass().getSimpleName());
}
functionMap.put(function.getClass(), function);
}
/**
* 处理服务器启动
*/
public static void handleOnServerStart() {
doHandleOnServerStart();
}
/**
* 处理服务器启动时对游戏类的处理
*/
private static void doHandleOnServerStart() {
for (IFunction handler : functionMap.values()) {
try {
handler.handleOnServerStart();
System.out.println("doHandleOnServerStart");
} catch (Exception e) {
//LogUtil.error(e);
System.err.println("have exception on do handleOnServerStart" + e);
}
}
}
/**
* 玩家登录时对游戏类的处理
* @param role
*/
public static void doHandleOnRoleLogin(Role role) {
for (IFunction handler : functionMap.values()) {
try {
handler.handleOnRoleLogin(role);
} catch (Exception e) {
// LogUtil.error(e);
}
}
}
/**
* 玩家离线时处理
* @param role
*/
public static void doHandleOnRoleLogout(Role role) {
if (role == null) {
return;
}
for (IFunction handler : functionMap.values()) {
try {
handler.handleOnRoleLogout(role);
} catch (Exception e) {
//LogUtil.error(e);
}
}
}
/**
* 每天凌晨0点处理
*/
public static void doHandleOnNextDay() {
for (IFunction handler : functionMap.values()) {
try {
handler.handleOnNextDay();
} catch (Exception e) {
//LogUtil.error(e);
}
}
}
}
通过FunctionManager在服务器启动、关闭,玩家登陆、离线,跨天的时候插入对应的逻辑方法,继承于IFunciton的Funciton子类只要实现上面那些注册了的方法就能拥有对应的特性。
4】实例使用
package com.xiu.function.activity;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.xiu.function.FunctionAdapter;
import com.xiu.push.Role;
/**
*活动逻辑
*
* @author xiu
* @version 2017年8月3日 下午2:21:56
*/
public class ActivityFunction extends FunctionAdapter {
/** 缓存玩家对应的活动列表 Map<rid, Map<aId,ActivityRole>> */
private ConcurrentHashMap<Long, Map<Long, ActivityRole>> activityRoleCacheMap = new ConcurrentHashMap<>();
/** 缓存活动列表 Map<aid, activity> */
private ConcurrentHashMap<Long, Activity> activityCacheMap = new ConcurrentHashMap<>();
@Override
public void handleOnRoleLogout(Role role) {
activityRoleCacheMap.clear();
}
@Override
public void handleOnServerShutdown() {
activityCacheMap.clear();
activityRoleCacheMap.clear();
}
}