亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

我如何使用課堂上選定的方法來限制我的客戶?

我如何使用課堂上選定的方法來限制我的客戶?

天涯盡頭無女友 2023-09-06 14:55:28
假設我有 1 個完整的類,其中包含大約 20 個提供不同功能的方法?,F在我們有多個客戶端使用此類,但我們希望他們的訪問受到限制。對于例如 -客戶端 1 - 訪問 method1/m3/m5/m7/m9/m11客戶端 2 - 訪問 method2/m4/m6/m8/m10/m12有什么辦法可以限制這種訪問嗎?我想到的一種解決方案:創建兩個擴展父類的新類并覆蓋不可訪問的方法并從中拋出異常。但是如果第三個客戶有不同的要求,我們必須為他們創建新的子類。還有其他方法可以做到這一點嗎?
查看完整描述

6 回答

?
偶然的你

TA貢獻1841條經驗 獲得超3個贊

創建兩個擴展父類的新類并覆蓋不可訪問的方法并從中拋出異常。但是如果第三個客戶有不同的要求,我們必須為他們創建新的子類。

這是一個糟糕的解決方案,因為它違反了多態性和里氏替換原則。這種方式會讓你的代碼不太清晰。

首先,你應該考慮一下你的類,你確定它沒有被方法重載嗎?您確定所有這些方法都與一個抽象相關嗎?也許,將方法分離到不同的抽象和類是有意義的嗎?

如果類中存在這些方法,那么您應該對不同的客戶端使用不同的接口。例如,您可以為每個客戶端創建兩個接口

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 {

}

之后,客戶端必須使用這些接口而不是類的具體實現來實現自己的邏輯。


查看完整回答
反對 回復 2023-09-06
?
aluckdog

TA貢獻1847條經驗 獲得超7個贊

您可以創建一個Interface1僅為 定義方法的Client1和一個Interface2僅為 定義方法的Client2。然后,您的班級實現Interface1Interface2。

當您聲明時,Client1您可以執行以下操作Interface1 client1:通過這種方法,client1只能訪問該接口的方法。

我希望這能幫到您。


查看完整回答
反對 回復 2023-09-06
?
青春有我

TA貢獻1784條經驗 獲得超8個贊

其他答案已經提出了慣用的方法。另一個想法是動態代理通過訪問檢查來修飾 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;


import java.lang.reflect.Method;


public class Main {


? ? interface API {

? ? ? ? void doAlpha(int arg);


? ? ? ? void doBeta(String arg);


? ? ? ? void doGamma(Object arg);

? ? }


? ? static class MyAPI implements API {

? ? ? ? @Override

? ? ? ? public void doAlpha(int arg) {

? ? ? ? ? ? System.out.println("Alpha");

? ? ? ? }


? ? ? ? @Override

? ? ? ? public void doBeta(String arg) {

? ? ? ? ? ? System.out.println("Beta");

? ? ? ? }


? ? ? ? @Override

? ? ? ? public void doGamma(Object arg) {

? ? ? ? ? ? System.out.println("Gamma");

? ? ? ? }

? ? }


? ? static class AlphaClient {

? ? ? ? void use(API api) {

? ? ? ? ? ? api.doAlpha(100);

? ? ? ? ? ? api.doBeta("100");

? ? ? ? ? ? api.doGamma(this);

? ? ? ? }

? ? }


? ? public static class MyACL implements ACL<AlphaClient, API> {

? ? ? ? @Override

? ? ? ? public boolean allowed(AlphaClient accessor, API target, Method method, Object[] args) {

? ? ? ? ? ? final String callerName = accessor.getClass().getName().toLowerCase();

? ? ? ? ? ? final String methodName = method.getName().toLowerCase().replace("do", "");

? ? ? ? ? ? return callerName.contains(methodName);

? ? ? ? }

? ? }



? ? public static void main(String[] args) {

? ? ? ? final MyACL acl = new MyACL();

? ? ? ? final API api = new MyAPI();

? ? ? ? final AlphaClient client = new AlphaClient();


? ? ? ? final API guardedAPI = acl.protect(client, api, API.class);

? ? ? ? client.use(guardedAPI);

? ? }

}

筆記:

  1. 不一定accessor是客戶端對象本身,它可以是幫助 ACL 識別客戶端的字符串鍵或令牌。

  2. 這里的 ACL 實現是基本的,更有趣的實現可能是從某個文件讀取 ACL 的實現,或者使用方法和客戶端注釋作為規則的實現。

  3. 如果你不想為API類定義接口,可以考慮使用javassist這樣的工具來直接代理類。

  4. 考慮其他流行的面向方面編程解決方案


查看完整回答
反對 回復 2023-09-06
?
慕斯709654

TA貢獻1840條經驗 獲得超5個贊

您應該創建一個包含所有方法的超類,然后在從先前定義的超類擴展的相應子類中提供客戶端特定的實現。

如果有一些方法是所有客戶端共同實現的,請將其實現留給超類。


查看完整回答
反對 回復 2023-09-06
?
largeQ

TA貢獻2039條經驗 獲得超8個贊

看來您對類和接口的用途有點困惑。據我所知,接口是定義軟件提供哪些功能的契約。這是來自官方java教程:

在軟件工程中的許多情況下,不同的程序員群體同意一份“合同”來闡明他們的軟件如何交互是很重要的。每個小組都應該能夠編寫自己的代碼,而無需了解其他小組的代碼是如何編寫的。一般來說,接口就是這樣的契約。

然后,您可以編寫一個實現此接口/契約的類,即提供實際執行指定操作的代碼。List接口ArrayList類都是這樣的示例。

接口和類具有訪問修飾符,但它們并非旨在指定特定客戶端的權限。它們指定其他軟件的可見內容,具體取決于定義的位置:類、包、子類、世界。例如,私有方法只能在定義它的類內部訪問。

再次來自官方Java教程:

訪問級別修飾符確定其他類是否可以使用特定字段或調用特定方法。有兩個級別的訪問控制:

  • 在頂層 - 公共或包私有(無顯式修飾符)。

  • 在成員級別 - 公共、私有、受保護或包私有(無顯式修飾符)。

也許您想要更強大的東西,例如訪問控制列表(ACL)。


查看完整回答
反對 回復 2023-09-06
?
藍山帝景

TA貢獻1843條經驗 獲得超7個贊

你的問題有點不清楚,導致可能的答案不同。我將嘗試涵蓋一些可能的領域:

對象封裝

如果您的目標是向僅提供某些功能或特定視圖的不同客戶端提供接口,則有多種解決方案。哪種最匹配取決于您班級的目的:

重構

這個問題在某種程度上表明你的班級負責不同的任務。這可能是一個指示符,表明您可以將其分解為提供不同接口的不同類。

原來的

class AllInOne {
    A m1() {}
    B m2() {}
    C m3() {}
}
client1.useClass(allInOneInstance);
client2.useClass(allInOneInstance);
client3.useClass(allInOneInstance);

衍生的

class One {
    A m1() {}
}class Two {
    B m2() {}
}class Three {
    C m3() {}
}
client1.useClass(oneInstance);
client2.useClass(twoInstance);
client3.useClass(threeInstance);

接口

如果您選擇將類放在一起(可能有充分的理由),則可以讓類實現對不同客戶端所需的視圖進行建模的接口。通過將適當接口的實例傳遞給客戶端,他們將看不到完整的類接口:

例子

class AllInOne implements I1, I2, I3 {
    ...
}interface I1 {
    A m1();
}

但請注意,客戶仍然可以投射到完整的班級,例如((AllInOne) i1Instance).m2().

遺產

這已經在其他答案中概述了。因此,我將在這里跳過這一點。我認為這不是一個好的解決方案,因為它在很多情況下可能很容易崩潰。

代表團

如果轉換對您來說存在風險,您可以創建僅提供所需接口并委托給實際實現的類:

例子

class Delegate1 {    private AllInOne allInOne;    public A m1() {        return allInOne.m1();
    }
}

實現這一點可以通過多種方式完成,具體取決于您的環境,例如顯式類、動態代理、代碼生成……

框架

如果您使用的是Spring等應用程序框架,您也許可以使用該框架中的功能。

方面

AOP 允許您攔截方法調用,并因此應用一些訪問控制邏輯。

安全

請注意,上述所有解決方案都不會為您提供實際的安全性。使用強制轉換、反射或其他技術仍然允許客戶端訪問完整功能。

如果您需要更強的訪問限制,我將簡要概述一些技術,因為它們可能取決于您的環境并且更加復雜。

類加載器

使用不同的類加載器,您可以確保代碼的某些部分無法訪問其范圍之外的類定義(例如在 tomcat 中用于隔離不同的部署)。

安全管理器

Java 提供了實現您自己的可能性,SecurityManager這提供了添加一些額外級別的訪問檢查的方法。

定制安全

當然,您可以添加自己的訪問檢查邏輯。但我不認為這對于 JVM 方法訪問來說是一個可行的解決方案。


查看完整回答
反對 回復 2023-09-06
  • 6 回答
  • 0 關注
  • 209 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號