Oop 设计模式以确保在方法B之前调用方法a
我有一个样本(不完整)类,如Oop 设计模式以确保在方法B之前调用方法a,oop,design-patterns,Oop,Design Patterns,我有一个样本(不完整)类,如 class ABC{ public: void login(); void query_users(); //other methods private: //member data } 这个类的使用方式应该是先调用login,然后才能调用query\u用户等其他方法。Login为其他方法设置一些私有成员数据。除了调用一个函数来检查成员数据是否设置在类中其他每个方法的开头之
class ABC{
public:
void login();
void query_users();
//other methods
private:
//member data
}
这个类的使用方式应该是先调用login,然后才能调用query\u用户等其他方法。Login为其他方法设置一些私有成员数据。除了调用一个函数来检查成员数据是否设置在类中其他每个方法的开头之外,还有什么更简单的方法来实现这一点吗 我不确定这是不是最好的方法,但您可以将
login()
设为私有,并将其作为构造函数的一部分调用,这将确保在对象创建时调用login()
,之后只能调用任何其他函数(除非您有静态函数)
当它从上到下运行时,它将首先工作。如果要确保登录成功,请从login()方法内部调用其他方法 比如:
我知道有两种方法,它们有很大的不同。您必须为任务选择合适的机制——在标准的基于类的OO语言(例如Java/C++/C#/Python)中,它们是我所知道的唯一两种方法。(我可能不熟悉不同范式中的其他方法。) 1.检查状态。 这已经在许多类中完成,这些类必须跟踪系统/备份资源的状态。两个常见的例子是(文件)流和数据库连接 “模板”可能类似于:
void Logon(credentials) { ..; loggedOn = true }
void DieUnlessLoggedIn { if (!loggedOn) { throw .. } }
void DoStuff () { DieUnlessLoggedIn(); .. }
虽然上述方法非常通用,但有些语言可能支持不变量(Eiffel)、装饰(Python)、注释、AOP或其他断言机制
这种方法对于可变世界中的动态状态非常有用:例如,“注销”后会发生什么?DoStuff
的状态再次无效,直到重新登录(如果允许)。但是,这种方法通常不能用于主流OOP语言中的编译时检查,因为运行时状态在编译时根本不可用
2.使用多种类型来表示状态。
创建两个单独的类型,以便类型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. & 2.使用状态检查和状态/角色特定类型。
当然,混合是完全可以接受的,而且上述两种方法并不相互排斥。分离角色可能会使一种类型(以及在其上调用的方法)依赖于另一种方法,同时仍然检查运行时状态(视情况而定)。如上所述,#1非常适合运行时保护(可以是高度动态的),而#2可以在编译时强制执行某些规则。您可以做的是创建ABC实例,形成一个静态工厂方法,返回您可以使用的实例。在伪代码中:
abc = ABC.login(); //sets all the state
users = abc.query_users();
如果您真的想遵循好的模式,您可以尝试使尽可能多的类不可变
这意味着您的构造函数将设置总状态(完成整个登录),然后方法调用的顺序将完全无关。我建议检查已设置的一些数据成员是安全的。我建议使用单个状态变量当然,另一种方法是使用两个对象。创建ABC对象的方法也调用login方法。这个外部对象是唯一可以提供ABC对象的对象。我写了一些关于可能使用注释的东西,然后我读了Mats Peterson的评论-我喜欢这种方法。基本上使用构建器模式或工厂。这对于登录函数来说是一个危险的框架:如果你设置一个if来检查它只完成了3次迭代或其他什么,然后取消它,那么应该递归地完成工作:PI必须同意答案#2,如果您使用这个过程,编译器甚至可以在运行时发生之前捕捉到这个问题,因为它不可能以错误的顺序完成。
login = new ServiceLogon(credentials)
access = login.Logon();
access.DoStuff(); // can't be called before obtained via Logon
abc = ABC.login(); //sets all the state
users = abc.query_users();