Pregunta

imaginar algo como esto:

import class B.*;


interface A supports A.testSum
{
   int sum( int a , int b ) access from B.calculator;

   testSum() { Assert(sum(1,1)==2); }

........


class B ...
{
  void calculator() {  A.sum(3,5); //ok }
  void someOtherMethod() { A.sum(0,3); //compile error }

la idea de los "soportes" es secundario pero relevante ya que la prueba se aplica a la interfaz en este caso (por lo que el lenguaje discriminaría entre una prueba de interfaz, que deben pasar todas las implementaciones y una prueba de aplicación, que es específico para el soldados de aplicación

pero la idea importante que quiero transmitir aquí es la semántica de control de acceso; Tenga en cuenta que A.sum con "el acceso de" palabra clave sólo puede ser llamado desde el método B.calculator. Todo lo demás se detecta como un error de tiempo de compilación. La idea aquí es hacer cumplir las restricciones arquitectónicas de una manera más granular. Si no agrega un "acceso desde" o simplemente añadido "el acceso de *" que significaría el comportamiento predeterminado de permitir que el método a ser llamado desde cualquier lugar. ¿Qué tipo de restricciones arquitectónicas? así, el tipo que se aplican manualmente cuando se hace un diseño en capas: Capa A (nivel más bajo) se utiliza desde la capa B (nivel intermedio), que está a su vez utiliza desde la capa C (nivel alto). Sin embargo, la capa B no es accesible desde la capa A y la capa C no es accesible desde ni A o B, pero es de otra manera pública (que podría ser lo que el usuario final tendrá acceso directo)

pregunta: ¿sabe cualquier lenguaje (incluyendo fuente-fuente de lenguajes intermedios) que soportan la semántica de arriba? puntos extra para la discusión de si este tipo de semántica sería contraproducente, peligrosa o simplemente alentar a un mal diseño

Actualización: hay otro caso de uso muy importante para este tipo de restricción:

programación orientada a eventos: Por lo general, el problema con el evento es que los eventos tienden a hacer demasiado, y la comprensión de la cadena de dependencias para los eventos pueden ser complicado

Así, por ejemplo, se podría definir que un controlador de eventos tiene solamente cierto conjunto de clases visibles que pueden interactuar para (o por el contrario, un cierto conjunto de objetos que no toque)

¿Fue útil?

Solución

Java soporta algo más o menos la misma cosa.

En primer lugar, la visibilidad de los campos y métodos se hacen cumplir en tiempo de ejecución, no es posible para el código de derivación sin privilegios a esto.

También puede hacer sus propios privilegios, y les conceda a ciertas partes del código. Por ejemplo, para abrir un archivo, el código que quiere acceder a un archivo FilePermission necesidades para ese archivo. Se puede hacer cualquier tipo de permiso que desea sin embargo, es posible hacer una llamada permiso SumPermission las que los controles Calculator antes de sumar, y sólo se conceda a cualquier clases que desea. dominios de protección se extienden a través clases, no métodos individuales en las clases, porque toda una clase se obtiene generalmente a partir de una sola fuente. El modelo, de hecho, es más profundo que lo que se propone. Cada clase en la pila (incluyendo la historia de las creaciones de hilo) que conduce a un control de seguridad debe tener el permiso, por lo que si algún código no confiable llama a su código que tiene SumPermission, fallará la comprobación de seguridad. Por supuesto esto es sólo por defecto, cada vez que tenga que hacer algo permisos necesidades, puede utilizar un bloque doPrivileged, para contar la próxima verificación para comprobar sus permisos única vez de las suyas y las personas que llaman.

Sin embargo, el esquema de seguridad predeterminado actual en Java tiene muchas limitaciones. Por un lado, código no confiable no puede subdividir sus permisos o definir sus propios permisos para el código no es de confianza anidada. Además, es un dolor Para protegerse de código no confiable que bloquea.

Es posible que desee comprobar hacia fuera E . En particular, se sigue el modelo de objetos-Capacidad. Está hecho para el código no es de confianza mutua para interactuar de forma segura, y tiene construcciones de nivel de idioma para evitar interbloqueos problemas.

Es perfectamente posible y factible implementar un comportamiento robusto entre el código mutuamente que no se confía en Java, pero E probablemente hará su trabajo mucho más fácil, y se ejecuta en la JVM por lo que aún debe ser capaz de utilizar las bibliotecas y librerías de Java desde cualquier otro idioma que utilizan la JVM.

Otros consejos

Esto suena un poco como un caso especial de la objeto-capacidad modelo . Tal vez hay lenguajes que implementan esto de alguna manera.

Del mismo modo, una rápida Google alrededor de "seguridad a nivel de método" me llevó a un par de cosas que la comunidad de Java de la empresa parece haber cocinado. Creo que este enfoque especializado a solo método llamado es un poco inútil. A menos que tenga una muy buena razón para hacer esto, creo que es probablemente una mala idea. Si usted está realmente interesado en hacerlo por alguna razón, entonces realmente el modelo debe ser conseguir que el receptor para comprobar que la fuente de invocación es de alguna conjunto permitido.

En cualquier caso, esto es, básicamente, rompiendo la mayoría de los modelos de programación bastante mal. Usted sería mucho mejor cumplimiento de condiciones previas e invariantes de clase para asegurar que cualquier invocación de método (desde cualquier lugar!) Es significativa o de buen comportamiento. Si usted lo está utilizando para hacer cumplir método de ordenación, que se puede lograr mediante la comprobación invariante (estática o en tiempo de ejecución), o modelos teóricos tales como Interfaz Autómatas .

Esto es factible en Ruby, aunque con una sintaxis diferente. Tome la siguiente:

module T
    def check
        raise unless self.is_a?(Ca)
        raise unless %r{in `good_func'} =~ caller.first #`
        true
    end
end

class Ca
    include T
    def good_func
        check
    end
    def bad_func
        check
    end
end

class Cb
    include T
    def good_func
        check
    end
    def bad_func
        check
    end
end

a = Ca.new
b = Cb.new

a.good_func
=> true
a.bad_func
=> (RuntimeError)

b.good_func
=> (RuntimeError)
b.bad_func
=> (RuntimeError)

Cuando se utiliza el módulo como una mezcla en, corresponde self a la clase que includes el módulo. caller devuelve la pila de llamadas actual y caller.first le consigue la primera entrada en la pila de llamadas (es decir, la función que llamó a éste).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top