Java 如何使用类中选定的方法限制客户端?
假设我有一个完整的类,包含大约20个提供不同功能的方法 现在我们有多个客户机使用这个类,但我们希望它们具有受限的访问权限 例如- 客户端1-访问method1/m3/m5/m7/m9/m11 客户端2-访问method2/m4/m6/m8/m10/m12 我有没有办法限制这种访问 我认为的一个解决方案:Java 如何使用类中选定的方法限制客户端?,java,oop,inheritance,encapsulation,abstraction,Java,Oop,Inheritance,Encapsulation,Abstraction,假设我有一个完整的类,包含大约20个提供不同功能的方法 现在我们有多个客户机使用这个类,但我们希望它们具有受限的访问权限 例如- 客户端1-访问method1/m3/m5/m7/m9/m11 客户端2-访问method2/m4/m6/m8/m10/m12 我有没有办法限制这种访问 我认为的一个解决方案: package com.example; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Invoca
package com.example;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@FunctionalInterface
public interface ACL<P, Q> {
boolean allowed(P accessor, Q target, Method method, Object[] args);
class ACLException extends RuntimeException {
ACLException(String message) {
super(message);
}
}
@SuppressWarnings("unchecked")
default Q protect(P accessor, Q delegate, Class<Q> dType) {
if (!dType.isInterface()) {
throw new IllegalArgumentException("Delegate type must be an Interface type");
}
final InvocationHandler handler = (proxy, method, args) -> {
if (allowed(accessor, delegate, method, args)) {
try {
return method.invoke(delegate, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
} else {
throw new ACLException("Access denies as per ACL");
}
};
return (Q) Proxy.newProxyInstance(dType.getClassLoader(), new Class[]{dType}, handler);
}
}
创建2个扩展父类的新类,重写不可访问的方法,并从中引发异常。
但是如果第三个客户有不同的需求,我们必须为他们创建新的子类
还有其他方法吗?您可以创建一个
接口1
,它只为客户端1
定义方法,以及一个接口2
,它只为客户端2
定义方法。然后,您的类实现了Interface1
和Interface2
当您声明Client1
时,您可以执行如下操作:interface1client1
。
使用这种方法,client1
只能访问此接口的方法
我希望这将对您有所帮助。您应该使用所有方法创建一个超类,然后在其相应的子类中提供特定于客户机的实现,这些子类从前面定义的超类扩展而来 如果有一些方法是所有客户机的通用实现,那么将它们的实现留给超类 创建2个扩展父类的新类并重写 无法访问,并从中引发异常。但是如果第三 客户有不同的需求,我们必须为其创建新的子类 他们 这是一个糟糕的解决方案,因为它违反了和。这样会使代码不那么清晰 首先,您应该考虑一下您的类,您确定它没有被方法重载吗?您确定所有这些方法都与一个抽象相关吗?也许,将方法分离到不同的抽象和类是有意义的 如果类中存在这些方法,那么应该针对不同的客户端使用不同的方法。例如,您可以为每个客户端创建两个接口
interface InterfaceForClient1 {
public void m1();
public void m3();
public void m5();
public void m7();
public void m9();
public void m11();
}
interface InterfaceForClient2 {
public void m2();
public void m4();
public void m6();
public void m8();
public void m10();
public void m12();
}
并在课堂上实施
class MyClass implements InterfaceForClient1, InterfaceForClient2 {
}
之后,客户端必须使用这些接口,而不是类的具体实现来实现自己的逻辑 其他答案已经给出了惯用的方法。另一个想法是用访问检查来装饰API 本质上,您可以生成一个代理API,该API对方法调用进行额外检查,以实现某种形式的访问控制 实施示例:
package com.example;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@FunctionalInterface
public interface ACL<P, Q> {
boolean allowed(P accessor, Q target, Method method, Object[] args);
class ACLException extends RuntimeException {
ACLException(String message) {
super(message);
}
}
@SuppressWarnings("unchecked")
default Q protect(P accessor, Q delegate, Class<Q> dType) {
if (!dType.isInterface()) {
throw new IllegalArgumentException("Delegate type must be an Interface type");
}
final InvocationHandler handler = (proxy, method, args) -> {
if (allowed(accessor, delegate, method, args)) {
try {
return method.invoke(delegate, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
} else {
throw new ACLException("Access denies as per ACL");
}
};
return (Q) Proxy.newProxyInstance(dType.getClassLoader(), new Class[]{dType}, handler);
}
}
package.com.example;
导入java.lang.reflect.InvocationHandler;
导入java.lang.reflect.InvocationTargetException;
导入java.lang.reflect.Method;
导入java.lang.reflect.Proxy;
@功能接口
公共接口ACL{
允许布尔值(P访问器、Q目标、方法、对象[]args);
类ACLException扩展了RuntimeException{
ACLException(字符串消息){
超级(信息);
}
}
@抑制警告(“未选中”)
默认Q保护(P访问器、Q委托、类dType){
如果(!dType.isInterface()){
抛出新的IllegalArgumentException(“委托类型必须是接口类型”);
}
最终调用处理程序=(代理、方法、参数)->{
if(允许(访问器、委托、方法、参数)){
试一试{
返回方法.invoke(委托,参数);
}捕获(调用TargetException e){
抛出e.getCause();
}
}否则{
抛出新的ACLException(“根据ACL拒绝访问”);
}
};
返回(Q)Proxy.newProxyInstance(dType.getClassLoader(),新类[]{dType},处理程序);
}
}
用法示例:
package com.example;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@FunctionalInterface
public interface ACL<P, Q> {
boolean allowed(P accessor, Q target, Method method, Object[] args);
class ACLException extends RuntimeException {
ACLException(String message) {
super(message);
}
}
@SuppressWarnings("unchecked")
default Q protect(P accessor, Q delegate, Class<Q> dType) {
if (!dType.isInterface()) {
throw new IllegalArgumentException("Delegate type must be an Interface type");
}
final InvocationHandler handler = (proxy, method, args) -> {
if (allowed(accessor, delegate, method, args)) {
try {
return method.invoke(delegate, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
} else {
throw new ACLException("Access denies as per ACL");
}
};
return (Q) Proxy.newProxyInstance(dType.getClassLoader(), new Class[]{dType}, handler);
}
}
package.com.example;
导入java.lang.reflect.Method;
公共班机{
接口API{
void doAlpha(int arg);
void doBeta(字符串arg);
void doGamma(对象arg);
}
静态类MyAPI实现API{
@凌驾
公共无效doAlpha(内部参数){
系统输出打印项次(“Alpha”);
}
@凌驾
公共无效多贝塔(字符串参数){
System.out.println(“Beta”);
}
@凌驾
公共void doGamma(对象arg){
系统输出打印项次(“伽马”);
}
}
静态类AlphaClient{
无效使用(API){
api.doAlpha(100);
api.doBeta(“100”);
api.doGamma(本);
}
}
公共静态类MyACL实现ACL以直接代理类
考虑其他流行的解决方案
您似乎对类和接口的用途有点困惑。据我所知,接口是定义软件提供哪些功能的契约。这来自java官方教程:
在软件工程中,有许多情况是
对于不同的程序员群体来说,同意“合同”很重要
这说明了他们的软件是如何相互作用的
能够编写自己的代码,而不知道对方是如何编写的
组的代码是编写的。一般来说,接口是这样的
合同
然后您可以编写一个实现此接口/约定的类,即提供实际执行指定内容的代码。List接口和ArrayList类都是这方面的示例
接口和类有访问修饰符,但它们不是为指定特定客户端的权限而设计的。它们指定其他软件的可见内容,具体取决于
class AllInOne implements I1, I2, I3 {
...
}
interface I1 {
A m1();
}
class Delegate1 {
private AllInOne allInOne;
public A m1() {
return allInOne.m1();
}
}