1. 程式人生 > 實用技巧 >Java—裝飾者設計模式

Java—裝飾者設計模式

一、裝飾者設計模式

概念:可以擴充套件原有物件的功能(比繼承更靈活),即定義一個介面


二、使用多執行緒為例子

2.1 介面中需要返回值,如何做?

public class Demo {
	public static void main(String[] args) {
		new Runnable() {
			
			@Override
			public void run() {
				// 此方法中需要返回物件,如何做
				// 可以通過成員變數的方式來獲取,需要新寫一個子類來實現Runnable介面
				
			}
		};
	}
}

解決方法:
Runnable的實現類

public class MyRunnable implements Runnable{
	
	public String result;

	@Override
	public void run() {
 		// 但是程式碼寫死了,如何改?
		result = "hello world!";
	}

}

測試類

public class Demo {
	public static void main(String[] args) throws Exception {
		MyRunnable runnable = new MyRunnable();
		
		Thread t1 = new Thread(runnable);
		t1.start();
		// 等待執行緒結束,獲取result不為null;
		// 否則,main方法開啟執行緒,執行緒有可能未執行完成,就執行main中接下來的程式碼
		t1.join();
		System.out.println(runnable.result);
	}
}

2.2 介面中的返回值不能寫死,如何做?(使用裝飾者設計模式,即定義一個介面來傳參)

介面裝飾器

/**
 * 裝飾器
 * @author hjn
 * @date   2019年12月10日 下午4:59:29
 *
 * @param <T>
 */
public interface Decorator<T> {
	/**
	 * 裝飾器
	 * @return 不知道傳遞的是什麼型別;可以使用泛型,可以達到通用的效果
	 */
	T decorator();
}

Runnable的實現類

public class MyRunnable<T> implements Runnable{
	
	public T result;
	
	private Decorator<T> decorator;
	
	// 外部可以通過set方法設定要傳遞的型別和值
	public void setDecorator(Decorator<T> decorator) {
		this.decorator = decorator;
	}


	@Override
	public void run() {
		// 呼叫的一定是實現類重寫的decorator方法
		result = decorator.decorator();
	}

}

測試類

public class Demo {
	public static void main(String[] args) throws Exception {
		MyRunnable<String> runnable = new MyRunnable<String>();
		runnable.setDecorator(new Decorator<String>() {
			
			@Override
			public String decorator() {
				return "hello world";
			}
		});
		
		MyRunnable<String> runnable2 = new MyRunnable<String>();
		runnable2.setDecorator(new Decorator<String>() {
			
			@Override
			public String decorator() {
				return "java";
			}
		});
		
		Thread t1 = new Thread(runnable);
		Thread t2 = new Thread(runnable2);
		t1.start();
		t2.start();
		// 等待執行緒結束,獲取result不為null;
		// 否則,main方法開啟執行緒,執行緒有可能未執行完成,就執行main中接下來的程式碼
		t1.join();
		t2.join();
		System.out.println(runnable.result);
		System.out.println(runnable2.result);
	}
}

但是,以上的程式存在有可能無節制地建立物件;因此,我們可以使用執行緒池的方法來建立


2.3 解決無節制建立物件

ThreadUtils

/**
 * 多執行緒工具
 * @author chenwei
 * @date 2019年5月24日 下午4:23:54
 */
public class ThreadUtils {
	/**執行緒鎖*/
	private static ExecutorService threadPool = null;
	/*使用靜態程式碼塊,只建立一次*/
	static {
		//獲取裝置最大執行緒池
//		threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
		//獲取當前cpu的執行緒數
		int threadCount = Runtime.getRuntime().availableProcessors();
		threadCount = threadCount <= 1?2:threadCount;//如果cpu只有一條執行緒預設給予2
		threadPool = new ThreadPoolExecutor(//建立一個有佇列的執行緒池,超出執行執行緒會放到佇列中等待
							threadCount,//
							threadCount*3,//最大執行緒數
			                60,//空閒執行緒存活時間
			                TimeUnit.MILLISECONDS,//時間單位
			                new LinkedBlockingQueue<Runnable>(threadCount*3));//佇列
	}
	
	/**
	 * 獲取執行緒池物件
	 * 
	 * @author chenwei
	 * @date 2019年5月24日 下午4:24:32
	 * @return
	 */
	public static ExecutorService getThreadPool() {
		return threadPool;
	}
	
	
}

測試類

public class Demo {
	public static void main(String[] args) throws Exception {
		MyRunnable<String> runnable = new MyRunnable<String>();
		runnable.setDecorator(new Decorator<String>() {
			
			@Override
			public String decorator() {
				return "hello world";
			}
		});
		
		MyRunnable<String> runnable2 = new MyRunnable<String>();
		runnable2.setDecorator(new Decorator<String>() {
			
			@Override
			public String decorator() {
				return "java";
			}
		});
		
		ExecutorService threadPool = ThreadUtils.getThreadPool();
		Future<?> submit = threadPool.submit(runnable);
		Future<?> submit2 = threadPool.submit(runnable2);
		
		// Future<?>中的get()為null時,表示執行緒執行完成
		while(true){
			if(submit.get() == null && submit2.get() == null){
				break;
			}
		}
		
		System.out.println(runnable.result);
		System.out.println(runnable2.result);
		
		// 關閉執行緒池
		threadPool.shutdown();
	}
}

使用倒計時鎖

public class Demo {
	public static void main(String[] args) throws Exception {
		// 倒計時鎖 -- 引數執行幾個執行緒就設定幾個值
		CountDownLatch countDownLatch = new CountDownLatch(2);
		MyRunnable<String> runnable = new MyRunnable<String>();
		runnable.setDecorator(new Decorator<String>() {
			
			@Override
			public String decorator() {
				// 倒計時,此方法寫線上程執行的run方法中
				countDownLatch.countDown();
				return "hello world";
			}
		});
		
		MyRunnable<String> runnable2 = new MyRunnable<String>();
		runnable2.setDecorator(new Decorator<String>() {
			
			@Override
			public String decorator() {
				countDownLatch.countDown();
				return "java";
			}
		});
		
		ExecutorService threadPool = ThreadUtils.getThreadPool();
		Future<?> submit = threadPool.submit(runnable);
		Future<?> submit2 = threadPool.submit(runnable2);
		
		// Future<?>中的get()為null時,表示執行緒執行完成
//		while(true){
//			if(submit.get() == null && submit2.get() == null){
//				break;
//			}
//		}
		
		// 等待子執行緒執行結束
		countDownLatch.await();
		
		System.out.println(runnable.result);
		System.out.println(runnable2.result);
		
		// 關閉執行緒池
		threadPool.shutdown();
	}
}