由于这次的东西比较简单,只是一个概念性的东西。所以先从一个游戏例子开始(石头剪刀布),假设我定义了这么一个接口
/**
* 石头:ItemOne
* 剪:ItemTwo
* 刀布:ItemThree
* 游戏
* @author Administrator
*
*/
public interface Item {
String compete(Item item);
String getName();
}
石头,剪刀,布一样都是item的实例,他们都可以和另外一个item比较。下面我按照不同的方式实现每一个类
- 石头(单路分发)
这一种可能我们初级阶段经常会这样写的一种方式
/**
* 石头
* @author Administrator
*
*/
public class ItemOne implements Item{
@Override
public String compete(Item item) {
if(item instanceof ItemOne) {
return "0";
}
if(item instanceof ItemTwo) {
return "1";
}
if(item instanceof ItemThree) {
return "-1";
}
return null;
}
@Override
public String getName() {
return "石头";
}
}
测试结果
这种实现方式其实本质上是可以实现功能,而且简单易懂,唯一的缺点就是后期新增了一个Item的话,这个方法必须修改,这就违反开闭原则
- 剪刀(普通二路)
这里需要改一下item接口,新增被每一个item比较的方法(有多少个实例就需要加多少个)
/**
* 石头:ItemOne
* 剪:ItemTwo
* 刀布:ItemThree
* 游戏
* @author Administrator
*
*/
public interface Item {
String compete(Item item);//比较this vs item
String itemCompeteThis(ItemOne itemOne);//石头 vs this
String itemCompeteThis(ItemTwo itemTwo);//剪刀 vs this
String itemCompeteThis(ItemThree itemThree);//布 vs this
String getName();
}
剪刀实现类
/**
* 剪刀
* @author Administrator
*
*/
public class ItemTwo implements Item{
@Override
public String compete(Item item) {
return item.itemCompeteThis(this);
}
@Override
public String itemCompeteThis(ItemOne itemOne) {
return "1";
}
@Override
public String itemCompeteThis(ItemTwo itemTwo) {
return "0";
}
@Override
public String itemCompeteThis(ItemThree itemThree) {
return "-1";
}
@Override
public String getName() {
return "剪刀";
}
}
测试结果
这个看起来比第一个确实好多了,如果在新增一个item的情况下,只需要重载一个itemCompeteThis方法,没有违背开闭原则,但是需要知道有多少个实现类
- 布(使用枚举实现多路分发)
这里的核心是使用一个枚举维护好所有item比对其他item的结果,代码如下
package com.javaSe.distribute;
/**
* 剪刀
* @author Administrator
*
*/
public class ItemThree{
public static enum Item{
ItemOne("石头","0","1","-1"),
ItemTwo("剪刀","-1","0","1"),
ItemThree("布","1","-1","0")
;
private String name,vItemOne,vItemTwo,vItemThree;
private Item(String name,String vItemOne, String vItemTwo, String vItemThree) {
this.name = name;
this.vItemOne = vItemOne;
this.vItemTwo = vItemTwo;
this.vItemThree = vItemThree;
}
public String getName() {
return name;
}
public String compete(Item item) {
switch (item) {
case ItemOne:
return vItemOne;
case ItemTwo:
return vItemTwo;
case ItemThree:
return vItemThree;
default:
return "";
}
}
}
// @Override
// public String compete(Item item) {
// return item.compete(this);
// }
// @Override
// public String itemCompeteThis(ItemOne itemOne) {
// return "-1";
// }
// @Override
// public String itemCompeteThis(ItemTwo itemTwo) {
// return "1";
// }
// @Override
// public String itemCompeteThis(ItemThree itemThree) {
// return "0";
// }
// @Override
// public String getName() {
// return "布";
// }
}
测试结果
个人认为,这个方式的唯一优点就是代码简洁了。
- 总结
通过上面的例子,相信大家可能知道什么是分发的概念了。其实java是只支持单路分发的,也就是说,如果要执行的操作包含了不止一个类型位置的对象时,那么java动态绑定只能处理一个未知对象,这时我们就需要使用多个方法确定多个未知对象,每个方法调用确定一个未知对象,这就叫多路分发。需要注意的是,要利用多路分发,就必须为每一个类型提供实际的方法调用,这在实现类很多的情况下,会变得很臃肿。这时可以考虑别的方式来处理这种问题了