【问题标题】:a design pattern or approach to handle access control of the fields of an object处理对象字段访问控制的设计模式或方法
【发布时间】:2016-04-05 21:44:54
【问题描述】:

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

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

但我的问题是,我想为不同的调用者指定被调用者的不同访问权限。

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

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

我已经有了以下一些想法,但是这些想法似乎太复杂了,并不理想。

那么有什么好的方法、设计模式,或者其他的东西来处理这个问题吗?

非常感谢

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

我的想法:

1.使用访问密钥类。

  • 创建一个类“访问密钥”。
  • 使用“游戏主机”类将“密钥”实例分配给不同的玩家。
  • 棋盘类实例有一个键权映射表。
  • 每次玩家向 board,它必须将它们的键实例作为参数提供给方法, 如果权限被拒绝,则抛出异常。

2.使用中介控制器类

  • 棋盘中有一个内部类“boardcontroller”。
  • 2个棋盘控制器子类,1个可以下白棋,另一个可以下黑棋。

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

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

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

在board类的“move”或“read”方法中,查看线程的callstack,知道调用者是否属于“player”类,是哪边(黑或白)。

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

有更好的主意吗?谢谢你

【问题讨论】:

  • 没有必要成为一些“设计模式”的东西,只要一个好的方法或技巧就可以了。
  • 考虑为此使用代理?

标签: java design-patterns acl access-rights


【解决方案1】:

无论您如何设置,您都可以选择使用反射或本机代码传递它。

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

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

【讨论】:

  • 是的,我有想过把棋盘写成一个服务进程,让玩家用restful什么的做IPC用棋盘来玩。但它似乎还是太复杂了。
  • @Porcelain 我同意,可能是这样,如果你有足够的决心,有办法解决这个问题。
【解决方案2】:

代理是你所需要的。

这种设计模式是控制对特定对象的访问,可以控制它们的创建或任何东西。

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

Reference

【讨论】:

  • 经过考虑,虽然还有一些细节需要处理,但类似代理模式的解决方案似乎可以接受。
【解决方案3】:

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

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

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

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

public interface ChessPiece {
    public Position getPosition();
}

所有棋子都放在棋盘上。所以下一步是设计一个可以访问所有ChessPieces 的棋盘。

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 来防止这种情况。

【讨论】:

  • 这是一个很好的例子。而不是由另一个实例(对象)作为代理,它只是使用同一实例的不同接口来处理访问控制。
  • 我认为在这个设计中,它可能还需要一个方法来检查一个对象是否属于特殊访问权限透视图(接口)的列表,例如PlayersChessPiece getPlayersChessPieceInterface ( ChessPiece cp ) { return (cp instanceof PlayersChessPiece) ? (PlayersChessPiece)cp : null; } ,对吧?
【解决方案4】:

也许这种访问控制设计模式会是一个解决方案: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!!!
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多