处理对象字段访问控制的设计模式或方法

时间:2016-01-01 08:11:12

标签: java design-patterns acl access-rights

我们知道,在许多OO程序语言中,我们可以使用一些访问修饰符来指定对象内部字段的访问范围。

例如,在java中,我们可以使用public,protected或private为该对象的所有调用者指定字段的访问范围。

但我的问题是,我想为不同的来电者指定被叫方的不同访问权限。

最重要的一点是:调用者类可以由其他程序员编写,但在我的主程序编写完成后,他们无法通过自己的实现来更改权限。

例如,假设国际象棋游戏程序中至少有3个实体,1个棋盘和2个玩家,我想让黑方玩家对棋盘上的所有国际象棋都“读取”访问权限,但只是“移动“对所有黑棋的访问权限,(并且只有在轮到它时才向右移动),反之亦然。”

我已经有了一些想法如下,但似乎这些想法太复杂而且不理想。

那么有没有什么好方法,设计模式或其他什么来处理这个问题?

非常感谢

// ============================================= ==================

我的想法:

1.使用访问密钥类。

  • 创建一个“访问密钥”类。
  • 使用“游戏主机”类将“关键”实例分配给不同的玩家。
  • 棋盘类实例有一个右键地图表。
  • 每次玩家执行“阅读”或“移动”动作时 它必须将其关键实例作为参数提供给方法, 如果权限被拒绝,则抛出异常。

2.使用中介控制器类

  • 棋盘内有一个内部的“boardcontroller”。
  • 2个董事会控制器子类,1个可以移动白棋,另一个可以移动黑棋。

(虽然我可以在这个子类中使用一些if-else来决定是否可以移动一些国际象棋,但我想让其他程序员编写播放器类,并让他们编写AI,所以这些子类使用的权限判断流程不能直接在播放器类中用作我的问题的方法。)

  • 将子板控制器实例分配给不同的播放器。

3.低级别方法(丑陋且不理想)

在棋盘类的“移动”或“读取”方法中,检查线程的callstack,知道是调用者属于类“播放器”,以及它是哪一侧(黑色或白色)。

// ============================================= ======================

有什么好主意吗?谢谢

4 个答案:

答案 0 :(得分:4)

代理就是您所需要的。

此设计模式控制对特定对象的访问,可以控制其创建或任何内容。

关于它的最好的部分是客户端不知道他正在使用代理。 只有部分是如果客户端调用方法,它没有访问权限,你可以抛出一些异常。在这种情况下,您必须为每个此类方法修改类接口以引发异常,实际实现不会这样做,但为了代理,这是一个很好的解决方案。

Reference

答案 1 :(得分:2)

无论你如何设置它,都可以选择通过反射或本机代码传递它。

唯一安全的方法是让组件在自己的进程中运行,这样它们就无法直接相互访问。它们可以作为服务运行,过滤访问它们的人员并限制可以执行的操作。即使这不是完全安全的。

但是,如果您通过方法调用使用访问密钥,则表示您具有一定程度的信任。如果你愿意承担一定程度的信任,那么也许你可以考虑一个更简单的模型。即,我不确定访问密钥对安全性的适当程度。

答案 2 :(得分:1)

  

处理对象字段的访问控制的设计模式或方法

每种类型都只通过privateprotectedpublic或包指定对字段和方法的访问控制。如果另一个类可以访问另一个对象 - 引用,则它只能调用方法或获取字段值。因此,您必须控制谁可以获得某个对象的引用。

即使代理通常是控制访问的解决方案,您也可以通过设计明确访问权限规则。

对于国际象棋游戏,我首先会设计一个名为ChessPiece的界面。由于每个玩家都可以看到所有国际象棋棋子,我会指定一个返回棋子位置的方法。

public interface ChessPiece {
    public Position getPosition();
}

所有国际象棋棋子都放在棋盘上。因此,下一步是设计一个棋盘,可以访问所有ChessPiece

public interface Chessboard {
    public Collection<ChessPiece> getChessPieces();
}

Player可以访问棋盘,因此可以看到所有棋子。但Player只能移动他自己的作品。因此Player必须能够访问一种特殊的棋子。

public class Player {

    private Collection<PlayersChessPiece> ownPieces;
    private Chessboard chessboard;

    public Player(Chessboard chessboard, Collection<PlayersChessPiece> ownPieces){
        this.chessboard = chessboard;
        this.ownPieces = ownPieces;
    }
}

由于玩家只能移动他自己的棋子,所以我将这个方面放入了设计中。

public interface PlayersChessPiece extends ChessPiece {
    public void move(Position position) throws MoveNotSupported;
}

这种设计背后的想法很简单。方法属于类,对象是某个类的实例。如果有人可以访问某个对象(引用),则只能调用某个方法。因此,访问权限可以简单地由将访问权限视角放在其他对象上的对象来表示。您只需确保为客户提供正确的参考。

当然有人可以使用反射破解对象并访问私有字段。您只能通过安装security manager来阻止此操作。

答案 3 :(得分:1)

也许这种访问控制设计模式是一个解决方案:https://www.javaworld.com/article/2075599/java-security/access-control-for-partial-exposure.html

这是使用模式的文章中的示例:

// ******** VirtualMethod ********
public abstract class VirtualMethod {
    public abstract void call();
}
// ******** Server ********
public class Server {

    private void shakeRattleAndRoll() {
        System.out.println("SHAKE ... RATTLE AN' ROLL!!!");
    }
    private class ShakeRattleAndRoll extends VirtualMethod {
        public void call() {
             shakeRattleAndRoll();
        }
    }
    public Client getClient() {
        return new Client(new ShakeRattleAndRoll());
    }

}
// ******** Client ********
public class Client {

    private VirtualMethod shakeRattleAndRoll;

    public Client(VirtualMethod shakeRattleAndRoll) {
        this.shakeRattleAndRoll = shakeRattleAndRoll;
    }

    public void demonstrateAccess() {
        shakeRattleAndRoll.call();
    }

}
// ******** Test ********
public class Test {
    public static void main(String[] args) {
        Server server = new Server();
        Client client = server.getClient();
        client.demonstrateAccess();           // Prints out:  SHAKE ... RATTLE AN' ROLL!!!
    }
}