我是一个相当新的Ada程序员.我读过Barnes的书(我可能会补充两次)甚至设法在Ada写一个公平的终端程序.我的主要语言是C++.
我目前想知道是否有办法在Ada中"保护"子程序调用,也许在Ada 2012中(我基本上什么都不知道).让我解释一下我的意思(尽管用C++术语).
假设你有一个Secret这样的类:
class Secret
{
private:
int secret_int;
public:
Set_Secret_Value( int i );
}
Run Code Online (Sandbox Code Playgroud)
现在这是常见的东西,不要暴露secret_int,只能通过访问函数来操纵它.但是,问题是任何有权访问Secret类型对象的人都可以操纵该值,无论该特定代码段是否应该这样做.因此,恶意改变secret_int的危险已经减少到任何人通过允许的函数改变secret_int,即使它发生在不应该操纵它的代码部分.
为了解决这个问题,我想出了以下结构
class Secret
{
friend class Secret_Interface;
private:
int secret_int;
Set_Secret_Value( int i );
Super_Secret_Function();
};
class Secret_Interface
{
friend class Client;
private:
static Set_Secret_Value( Secret &rc_secret_object, int i )
{
rc_secret_object.Set_Secret( i );
}
};
class Client
{
Some_Function()
{
...
Secret_Interface::Set_Secret_Value( c_object, some-value );
...
}
}
Run Code Online (Sandbox Code Playgroud)
现在,类Secret_Interface可以确定哪些其他类可以使用它的私有函数,并通过这样做间接地实现暴露给类Secret的函数Secret_Interface.这样,类Secret仍然具有私有函数,这些函数不能被类外的任何人调用,例如函数Super_Secret_Function().
好吧,我想知道在Ada中是否有任何类型的东西是可能的.基本上我的愿望是能够说:
Code A may only be executed by code B but not by anybody else
Run Code Online (Sandbox Code Playgroud)
谢谢你的帮助.
编辑:我在这里添加一个图表,其程序结构就像我想到的那样,这表明我的意思是数据结构在软件的广泛区域内的传输,记录的定义,创建和使用应该在代码中发生其他部分是不完整的

我认为关键是要意识到,与C++和其他语言不同,Ada的主要顶级单位是package,并且可见性控制(即公共与私有)是基于每个包,而不是每个类型(或每个 - 基础.我不确定我说得对,但希望下面会解释一下.
friendC++ 的主要目的之一是,您可以编写两个(或更多)密切相关的classes,它们都参与实现一个概念.在这种情况下,有意义的是,一个类中的代码能够更直接地访问另一个类中的代码,因为它们在一起工作.我假设在你的C++示例中,Secret并且Client有这种亲密的关系.如果我正确理解C++,它们都必须在同一个源文件中定义; 如果你说friend class Client,那么Client必须在同一个源文件中的某个地方定义类(并且它不能在之前定义,因为此时尚未声明Secret或Secret_Interface尚未声明的方法).
在Ada中,您只需在同一个包中定义类型即可.
package P is
type Secret is tagged private;
type Client is tagged private;
-- define public operations for both types
private
type Secret is tagged record ... end record;
type Client is tagged record ... end record;
-- define private operations for either or both types
end P;
Run Code Online (Sandbox Code Playgroud)
现在,body P将包含两种类型的公共和私有操作的实际代码.在所有代码package body的P访问中定义的那些事情P的private一部分,无论他们经营哪种类型的.事实上,所有代码都可以访问这两种类型的完整定义.这意味着在a上运行的过程Client可以调用在a上运行的私有操作,Secret实际上它可以Secret直接读写记录组件.(反之亦然.)对于class习惯于大多数其他OOP语言使用的范例的程序员来说,这似乎很奇怪,但它在Ada中运行良好.(事实上,如果你不需要Secret除了实现之外的其他任何东西都可以访问Client,那么类型及其操作可以在private部分中定义P,或者package body.)这种安排不违反OOP背后的原则(封装) ,信息隐藏),只要这两种类型真正实现两个相干概念的实现.
如果这不是你想要的,也就是说,如果有什么Secret,并Client没有那么密切的关系,那么我需要看到一个更大的例子,找出你想实现只是什么样的使用情况.
更多想法:在查看图表之后,我认为您尝试解决问题的方式是劣质设计 - 如果您愿意,则采用反模式.当你编写一个"模块"(无论是什么意思 - 一个类或一个包,或者在某些情况下,两个或多个密切相关的类或包相互协作)时,该模块定义了其他模块如何使用它 - 什么是公共操作它提供了它的对象,以及这些操作的功能.
但是根据合同,模块(我们称之为M1)应该以相同的方式工作,无论其他模块调用它,以及如何.M1将获得一系列"消息",指示其执行某些任务或返回某些信息; M1不应该关心这些消息的来源.特别是,M1不应该对使用它的客户端的结构做出决定.通过M1法令"只能从包ABC中调用程序XYZ",M1对使用它的客户施加了结构要求.我相信这会导致M1与程序的其他部分紧密耦合.这不是好设计.
但是,对于使用 M1 的模块在内部执行某种类型的控制可能是有意义的.假设我们有一个"模块"M2实际上使用了许多软件包作为其实现的一部分.M2中的"主"包(M2的客户端用来让M2执行其任务)使用M1创建一个新对象,然后将该对象传递给其他几个完成工作的包.这似乎是一个合理的设计目标找到一种方式,能够M2传递对象到一些包或子程序,而不给他们,说,更新对象的能力,但它传递给其他的包或子程序是将具有这种能力.
有一些解决方案可以防止大多数事故.例如:
package M1 is
type Secret is tagged private;
procedure Harmless_Operation (X : in out Secret);
type Secret_With_Updater is new Secret with null record;
procedure Dangerous_Operation (X : in out Secret_With_Updater);
end M1;
Run Code Online (Sandbox Code Playgroud)
现在,可以采用"秘密"对象但不应该具有更新能力的软件包将具有使用Secret'Class参数定义的过程.M2会创建一个Secret_With_Updater对象; 由于此对象类型是Secret'Class,它可以作为参数传递给带Secret'Class参数的过程.但是,这些程序无法调用Dangerous_Operation其参数; 那不会编译.
带Secret'Class参数的包仍然可以通过类型转换调用危险操作:
procedure P (X : in out Secret'Class) is
begin
-- ...
M1.Secret_With_Updater(X).Dangerous_Operation;
-- ...
end P;
Run Code Online (Sandbox Code Playgroud)
语言不能阻止这种情况,因为它不能使Secret_With_Updater某些包可见而不能使其他包(不使用子包层次结构).但是偶然做这件事会更难.如果你真的希望更进一步,甚至阻止这一点(如果你认为会有一个程序员,他们对良好的设计原则的理解太差,以至于他们愿意编写这样的代码),那么你可以更进一步:
package M1 is
type Secret is tagged private;
procedure Harmless_Operation (X : in out Secret);
type Secret_Acc is access all Secret;
type Secret_With_Updater is tagged private;
function Get_Secret (X : Secret_With_Updater) return Secret_Acc;
-- this will be "return X.S"
procedure Dangerous_Operation (X : in out Secret_With_Updater);
private
-- ...
type Secret_With_Updater is tagged record
S : Secret_Acc;
end record;
-- ...
end M1;
Run Code Online (Sandbox Code Playgroud)
然后,为了创建一个秘密,M2会调用一些东西来创建一个Secret_With_Updater,它返回一个可以访问Secret的记录.然后它将传递X.Get_Secret给那些不允许调用的程序Dangerous_Operation,但X它本身传递给那些允许的程序.(您可能也可以声明S : aliased Secret,声明Get_Secret返回access Secret并使用它来实现return X.S'access.这可以避免潜在的内存泄漏,但它也可能遇到可访问性检查问题.我没有尝试过.)
无论如何,也许这些想法中的一些可以通过强制M1了解使用它的应用程序的结构来帮助实现您想要完成的任务而不引入不必要的耦合.这很难说,因为你对这个问题的描述,即使是图表,对于我来说仍然是一个过于抽象的层次,看你真正想要做什么.
| 归档时间: |
|
| 查看次数: |
250 次 |
| 最近记录: |