1. 程式人生 > >模擬實現任務分配(模板模式)

模擬實現任務分配(模板模式)

在實際應用中有這樣一個場景:有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
  • 模版方法和策略模式都封裝了演算法,一個用組合(策略模式),一個用繼承(模版方法)。

 

每天努力一點,每天都在進步。