本人最常用的模式是裝飾模式,一直搞不太清楚其跟代理模式的區別,今天來區分一下。
代理模式
代理模式是結構設計模式之一,也是非常好理解的一種模式。根據GoF中所說:
爲其他的對象提供代理或者佔位符,來控制其訪問的權限
從上面的定義就可以知道代理模式的場景主要是當我們需要提供訪問訪問控制的時候使用的。
假設我們有一個類,要在一個系統上面運行一些命令。在服務器端這個類工作的很正常,但是如果我們想根據這個類做一個客戶端程序,那麼就會有一些問題。因爲基於這個類實現的客戶端程序也有相同的權限來刪除系統文件或者更改一些你不想讓它修改的配置等等。
我們可以通過創建一個代理的類來支持客戶端的訪問控制。
原執行類
參考如下代碼:
package net.ethanpark.design.proxy;
public interface CommandExecutor {
public void runCommand(String cmd) throws Exception;
}
package net.ethanpark.design.proxy;
import java.io.IOException;
public class CommandExecutorImpl implements CommandExecutor {
@Override
public void runCommand(String cmd) throws IOException {
//some heavy implementation
Runtime.getRuntime().exec(cmd);
System.out.println("'" + cmd + "' command executed.");
}
}
上面的代碼就是原始的執行類,用來直接在系統上面執行命令用的。
代理類
現在我們可以提供一個功能:只有admin用戶纔有全部的權限,如果用戶不是admin,那麼則只能執行部分有限的命令。下面就是簡單的代理類實現:
package net.ethanpark.design.proxy;
public class CommandExecutorProxy implements CommandExecutor {
private boolean isAdmin;
private CommandExecutor executor;
public CommandExecutorProxy(User user){
if(user.getUsername().equals("admin"))
isAdmin=true;
executor = new CommandExecutorImpl();
}
@Override
public void runCommand(String cmd) throws Exception {
if(isAdmin){
executor.runCommand(cmd);
}else{
if(cmd.trim().startsWith("rm")){
throw new Exception("rm command is not allowed for non-admin users.");
}else{
executor.runCommand(cmd);
}
}
}
}
package net.ethanpark.design.proxy;
public class User {
private String username;
private String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
測試類
下面是測試類:
package net.ethanpark.design.test;
import net.ethanpark.design.proxy.CommandExecutor;
import net.ethanpark.design.proxy.CommandExecutorProxy;
public class ProxyPatternTest {
public static void main(String[] args){
CommandExecutor executor = new CommandExecutorProxy(new User("notAdmin", "some password"));
try {
executor.runCommand("ls -ltr");
executor.runCommand(" rm -rf abc.pdf");
} catch (Exception e) {
System.out.println("Exception Message::"+e.getMessage());
}
}
}
現在運行測試代碼,則輸出如下:
'ls -ltr' command executed.
Exception Message::rm command is not allowed for non-admin users.
代理模式通常用來控制訪問或者爲原有實現提供包裹實現來提高性能。
Java RMI包就使用了代理模式,有興趣的人可以參考源碼。