【设计模式系列】用代理模式避免rm -rf /*

2,025 阅读3分钟

这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战

前言

也许你没有使用过Linux,但是一定听说过rm -rf /* 的传说,这个命令会将系统中所有的文件删除,直接导致操作系统无法使用,只能重装系统,如果在生产环境执行基本上是灾难。

rmrf.gif

那么实际管理过程中,肯定不会让开发人员具备能执行这么高权限的账号,只有运维人员或者运维老大才有这样的权限。今天我们就用设计模式中的来讲一讲,操作系统是如何实现对于不同用户来控制访问权限的。

代理模式定义

定义: 为另一个对象提供代理或占位符以控制对它的访问。

代理模式是一种结构型的设计模式,其作用主要是控制对一个已有服务或对象的访问。

定义本身非常清楚,当我们想要提供对功能的访问控制时,就会使用代理设计模式。

代理模式实现

在我们开头的例子中,操作系统中具备执行命令的功能,我们假设这个功能在一个对象中,如果我们想把这个功能开放给所有的用户(客户端),那可能会有严重的问题,因为客户端会发出命令来删除一些系统文件或更改一些你不想要的设置,比如执行rm -rf /*

这种问题怎么解决呢?我们可以对这个具备执行命令能力的对象建立一个代理,在代理类中对于不同的用户进行访问权限控制。

代理模式主类

由于我们是根据接口编写Java代码的,下面是我们的接口及其实现类。

public interface CommandExecutor {

	public void runCommand(String cmd) throws Exception;
}

接口的具体实现:

import java.io.IOException;

public class CommandExecutorImpl implements CommandExecutor {
	@Override
	public void runCommand(String cmd) throws IOException {
                //执行操作系统命令
		Runtime.getRuntime().exec(cmd);
		System.out.println("'" + cmd + "' command executed.");
	}
}

代理模式代理类

现在我们想让管理员用户可以执行所以命令,如果不是管理员用户,那么只允许执行部分命令。下面一个非常简单的代理类实现。

public class CommandExecutorProxy implements CommandExecutor {

	private boolean isAdmin;
    
	private CommandExecutor executor;
	
	public CommandExecutorProxy(String user){
		if("admin".equals(user) || "root".equals(user)) 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);
			}
		}
	}
}

代理模式客户端


public class ProxyPatternTest {

	public static void main(String[] args){
		CommandExecutor executor = new CommandExecutorProxy("xiaohei");
		try {
			executor.runCommand("ls -ltr");
			executor.runCommand(" rm -rf /*");
		} 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包中也使用代理模式。

代理模式类图

代理模式和适配器模式的区别

你可能会发现代理模式和适配器模式很相似,它俩有什么区别呢?

适配器模式的目的是为了改变被适配对象,而代理模式不会对被代理对象进行改变。

代理模式和装饰器模式的区别

与装饰器模式比较,装饰器模式的目的是对被代理对象的功能进行增强,代理模式是对被代理对象的访问进行控制。

小结

以上时关于代理模式的内容,理解代理模式的关键点,代理模式的目的是为了对被代理对象的访问进行控制。

我是小黑,如果对你理解代理模式有帮助,点个赞是对我最大的肯定和鼓励!