模擬實現任務分配(模板模式)
阿新 • • 發佈:2018-11-01
在實際應用中有這樣一個場景:有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
- 模版方法和策略模式都封裝了演算法,一個用組合(策略模式),一個用繼承(模版方法)。