我有一个样本(不完整)类,如
class ABC{
public:
void login();
void query_users();
//other methods
private:
//member data
}
此类的使用方式应首先调用登录,然后才能调用其他方法,如query_users等。 Login为其他方法设置了一些私有成员数据。有没有更简单的方法来实现这个,除了调用一个函数来检查成员数据是否在类中的每个其他方法的开头设置?
答案 0 :(得分:4)
我知道有两种一般的方法,它们有很大不同。你必须选择适当的机制来完成任务 - 在基于标准类的OO语言中(例如Java / C ++ / C#/ Python),它们是我所知道的唯一两种方法。 (在我不熟悉的不同范例中可能还有其他方法。)
这已在许多必须跟踪系统/支持资源状态的类中完成。两个常见的例子是(文件)流和数据库连接。
“模板”可能如下所示:
void Logon(credentials) { ..; loggedOn = true }
void DieUnlessLoggedIn { if (!loggedOn) { throw .. } }
void DoStuff () { DieUnlessLoggedIn(); .. }
虽然上述方法非常通用,但某些语言可能支持不变量(Eiffel),装饰(Python),注释,AOP或其他断言机制。
此方法对于可变世界中的动态状态非常有用:例如“退出”后会发生什么? DoStuff
的状态再次无效,直到重新登录(如果允许)。但是,这种方法通常不能用于主流OOP语言的编译时检查,因为运行时状态在编译时根本不可用。
创建两个单独的类型,例如ServiceLogon类型(方法Logon
)创建ServiceAccess(方法DoStuff
)。因此,DoStuff
只能在从Logon
(在ServiceLogon上)创建后调用(在类型ServiceAccess上)。这很适合在隐藏成员的静态语言中强制执行调用顺序语义 - 因为如果错误,程序将无法编译。
login = new ServiceLogon(credentials)
access = login.Logon();
access.DoStuff(); // can't be called before obtained via Logon
使用类型来编码附加状态可能过于复杂,因为它可能破坏基于类的类型系统,但在“构建器”和“存储库”模式等中是有用的;基本上,如果类型需要拆分以维持SRP,请询问,然后考虑这种方法。
这种方法无法在没有合并状态检查的情况下完全处理像“注销”这样的事情,因为ServiceAccess(在干净的意义上)总是表示相同的状态,因为它在类型中被编码。
答案 1 :(得分:1)
您可以做的是创建一个ABC实例,形成一个静态工厂方法,返回您可以使用的实例。在伪代码中:
abc = ABC.login(); //sets all the state
users = abc.query_users();
答案 2 :(得分:0)
我不确定这是最好的方法,但你可以使login()
私有并将其作为构造函数的一部分来调用,这将确保在创建对象时和之后调用login()
只能调用任何其他函数(除非你有静态函数)
class ABC{
public ABC(credentials){
login(credentails);
}
public:
void query_users();
//other methods
private:
void login();
//member data
}
答案 3 :(得分:0)
当它从上到下时,它将首先工作。如果要确保登录成功,请从login()方法中调用其他方法。
像:
public void login(){
//do login code
if(//code for login check){
//run other methods
}
else{
login(); //re-run login workings
}
}
答案 4 :(得分:0)
如果你真的想要遵循良好的模式,你可以尝试让尽可能多的类不可变。
这意味着你的构造函数设置了总状态(完成整个登录),然后方法调用的顺序完全无关紧要。