bal*_*486 2 oop design-patterns
我有一个示例(不完整)类
class ABC{
public:
void login();
void query_users();
//other methods
private:
//member data
}
Run Code Online (Sandbox Code Playgroud)
此类的使用方式应首先需要调用登录名,然后才可以调用其他方法(例如query_users等)。登录设置一些私有成员数据供其他方法使用。除了调用检查类中每个其他方法的开始是否设置了成员数据的函数之外,还有其他更简单的方法来实现此目的吗?
我知道有两种通用方法,它们之间有很大的不同。您必须为任务选择适当的机制-在基于标准类的OO语言(例如Java / C ++ / C#/ Python)中,它们是我所知道的仅有的两种方法。(我不熟悉其他范式中的其他方法。)
已经在许多必须跟踪系统/支持资源状态的类中完成了此操作。两个常见的示例是(文件)流和数据库连接。
一个“模板”可能看起来像:
void Logon(credentials) { ..; loggedOn = true }
void DieUnlessLoggedIn { if (!loggedOn) { throw .. } }
void DoStuff () { DieUnlessLoggedIn(); .. }
Run Code Online (Sandbox Code Playgroud)
尽管上述方法非常通用,但是某些语言可能支持不变式(Eiffel),修饰(Python),注释,AOP或其他声明机制。
这种方法对于可变世界中的动态状态很有用:例如,“注销”之后会发生什么?在DoStuff重新登录之前(如果允许),状态再次无效。但是,这种方法通常不能用于主流OOP语言中的编译时检查,因为运行时状态在编译时根本不可用。
创建两个单独的类型,以使ServiceLogon(method Logon)类型创建ServiceAccess(method DoStuff)。因此DoStuff,只能从Logon(在ServiceLogon上)创建后才能调用(在ServiceAccess类型上)。这对于在成员隐藏的情况下以静态语言强制执行调用顺序语义非常有效-因为如果错误,程序将无法编译。
login = new ServiceLogon(credentials)
access = login.Logon();
access.DoStuff(); // can't be called before obtained via Logon
Run Code Online (Sandbox Code Playgroud)
使用类型对附加状态进行编码可能会过于复杂,因为它可能破坏基于类的类型系统,但在“构建器”和“存储库”模式等中很有用;基本上,请问是否要拆分类型以维护SRP,然后考虑采用这种方法。
这种方法不能完全不处理“登出”之类的问题,而不能合并状态检查,因为ServiceAccess类型(从干净的意义上来说)总是代表相同的状态,因为它以类型进行编码。
当然,混合是完全可以接受的,并且以上两种方法不是互相排斥的。在仍然适当检查运行时状态的同时,将使一种类型的角色(以及由此调用其的方法)依赖于另一种方法分离出来可能是有意义的。如上所述,#1非常适合运行时防护(可以高度动态化),而#2可以在编译时强制执行某些规则。