Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使用类中选定的方法限制客户端?_Java_Oop_Inheritance_Encapsulation_Abstraction - Fatal编程技术网

Java 如何使用类中选定的方法限制客户端?

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

假设我有一个完整的类,包含大约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.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();
        }
    }