在实际应用中有这样一个场景:有m台服务器,有n个任务,需要把这n个任务按一定策略分配给m台服务器来执行,请按以下要求实现该场景:
1、使用List列表代表服务器(列表中每个元素为一个IP地址);
2、使用List列表代表任务(列表中每个元素为任务ID);
3、分配的过程就是把IP地址与任务ID映射上的过程;
4、策略要支持多个,如按IP地址随机、按任务数量平分等,策略需要支持可扩展(扩展时不用修改已经实现好的策略);
1、实体类定义:
//服务器实体类
public class Service {
private String IP;
private String serviceName;
}
//任务实体类
public class Task {
private Integer taskId;
private String taskName;
}
2、抽象父类定义(所有的策略实现都需要继承该类)
public abstract class AbstractTaskAllocation {
/**
* 具体的整个过程 在这里定义操作实现的步骤
*/
protected void doTaskAllocation(List<Service> serverList, List<Task> taskList) {
// 1、准备阶段,可以进行一些数据初始化的操作
this.preparation(serverList, taskList);
// 2、把IP地址与任务ID映射上阶段
Map<Object, String> serviceTaskMapping = this.setMapping(serverList, taskList);
// 3、结果返回阶段
this.getResult(serviceTaskMapping);
}
/**
* 1、准备阶段
*/
public abstract void preparation(List<Service> serverList, List<Task> taskList);
/**
* 2、把IP地址与任务ID映射上阶段
*
* @param taskList
* @param serverList
*/
public abstract Map<Object, String> setMapping(List<Service> serverList, List<Task> taskList);
/**
* 3、结果返回阶段,分配完后续处理
*/
public void getResult(Map<Object, String> serviceTaskMapping){
// 分配状态查询
for (Entry<Object, String> entrySet : serviceTaskMapping.entrySet()) {
System.out.println("服务器IP: " + entrySet.getValue() + " === 任务ID: " + entrySet.getKey());
}
}
}
3、平均分配策略:
public class AverageTaskAllocation extends AbstractTaskAllocation {
// 进行一些参数校验之类的
@Override
public void preparation(List<Service> serverList, List<Task> taskList) {
if (serverList == null || serverList.size() < 1) {
System.out.println("没有可用的服务器!");
}
if (taskList == null || taskList.size() < 1) {
System.out.println("暂无需要处理的任务!");
}
}
// 设置服务器和任务之间的隐射关系
@Override
public Map<Object, String> setMapping(List<Service> serverList, List<Task> taskList) {
// map key_value 的形式存储服务器和任务的映射关系 id : ip
//Map<Object, String> serviceTaskMapping = new HashMap<Object, String>();
Map<Object, String> serviceTaskMapping = new TreeMap<>();
// 任务平均分配 参考HashMap 的分配原理
int serverCount = serverList.size();
for (int i = 0; i < taskList.size(); i++) {
int taskAddress = i % serverCount;
serviceTaskMapping.put(taskList.get(i).getTaskId(), serverList.get(taskAddress).getIP());
//serviceTaskMapping.put(taskList.get(i).getTaskName(), serverList.get(taskAddress).getServiceName());
}
return serviceTaskMapping;
}
/*@Override
public void getResult(Map<Object, String> serviceTaskMapping) {
// 分配状态查询
for (Entry<Object, String> entrySet : serviceTaskMapping.entrySet()) {
System.out.println("服务器IP: " + entrySet.getValue() + " === 任务ID: " + entrySet.getKey());
}
}*/
}
4、随机分配策略:
public class RandomTaskAllocation extends AbstractTaskAllocation {
// 进行一些参数校验之类的
@Override
public void preparation(List<Service> serverList, List<Task> taskList) {
if (serverList == null || serverList.size() < 1) {
System.out.println("没有可用的服务器!");
}
if (taskList == null || taskList.size() < 1) {
System.out.println("暂无需要处理的任务!");
}
}
// 设置服务器和任务之间的隐射关系
@Override
public Map<Object, String> setMapping(List<Service> serverList, List<Task> taskList) {
// map key_value 的形式存储服务器和任务的映射关系 id : ip
Map<Object, String> serviceTaskMapping = new HashMap<Object, String>();
// 设置的是随机事件 0或者1 各50%,保证随机分配性
// 服务器的数量,就是任务分配的概率
int serverCount = serverList.size();
Random r = new Random();
for (int i = 0; i < taskList.size(); i++) {
Integer serverId = r.nextInt(serverCount);
serviceTaskMapping.put(taskList.get(i).getTaskId(), serverList.get(serverId).getIP());
}
return serviceTaskMapping;
}
@Override
public void getResult(Map<Object, String> serviceTaskMapping) {
// 可以覆盖父类,进行一些子类特殊操作
}
}
5、测试类:
public class TaskAllocationTest {
public static void main(String[] args) {
List<Service> serverList = new ArrayList<>();
List<Task> taskList = new ArrayList<>();
// 添加服务器
for (int i = 1; i < 11; i++) {
Service service = new Service();
service.setIP("10.1.10.3" + i);
service.setServiceName("我是第"+i+"台服务器");
serverList.add(service);
}
// 添加任务
for (int i = 0; i < 500; i++) {
Task task = new Task();
task.setTaskId(i + 1);
task.setTaskName("我是第"+i+"个任务");
taskList.add(task);
}
// 随机分配策略:
AbstractTaskAllocation randomTaskAllocation = new RandomTaskAllocation();
randomTaskAllocation.doTaskAllocation(serverList, taskList);
// 平均分配任务策略
AbstractTaskAllocation averageTaskAllocation = new AverageTaskAllocation();
averageTaskAllocation.doTaskAllocation(serverList, taskList);
}
}
6、模板模式要点(不熟悉可以去看设计模式那节)
- 模版方法定义了算法的步骤,把这些步骤的实现延迟到了子类。
- 模版方法模式为我们提供了一种代码复用的重要技巧。
- 模版方法的抽象类可以定义具体方法、抽象方法和钩子。
- 抽象方法由子类实现。
- 为了防止子类改变模版方法中的算法,可以将模版方法声明为final
- 模版方法和策略模式都封装了算法,一个用组合(策略模式),一个用继承(模版方法)。