我已经做了一个工厂方法,它应该启动一个数据库( cassandra
)并连接到它或应返回现有会话。到数据库的连接是静态字段。
class EmbeddedCassandraManager {
def getCassandra() = {
if(EmbeddedCassandraManager.cassandraConnection.isDefined) //return existing instance
{
(EmbeddedCassandraManager.testCassandra,EmbeddedCassandraManager.cassandraConnection)
}
else {
EmbeddedCassandraManager.startCassandra()
}
}
def closeCassandra() = {
EmbeddedCassandraManager.closeCassandra()
}
}
object EmbeddedCassandraManager {
val factory = new EmbeddedCassandraFactory
//can I do the logic without using var?
var (testCassandra,cassandraConnection) = startCassandra()
def closeCassandra() = {
cassandraConnection.get.close()
cassandraConnection = None
testCassandra.stop()
}
def startCassandra():(Cassandra,Option[CassandraConnection]) = {
val testCassandra = factory.create()
testCassandra.start()
val cassandraConnectionFactory:DefaultCassandraConnectionFactory = new DefaultCassandraConnectionFactory();
val localCassandraConnection:Option[CassandraConnection] = try{
val connection = cassandraConnectionFactory.create(testCassandra)
Some(connection)
}catch{
case exception:Throwable => {
throw exception
}
}
this.cassandraConnection = localCassandraConnection
(testCassandra,this.cassandraConnection)
}
}
我能够创建逻辑的唯一方法是使用 var
对于 cassandraConnection
. 有没有一个模式我可以用来避免使用 var
?
在一次测试中,我不得不停下来 cassandra
测试数据库未运行时连接是否未建立。这会使现有连接过时。没有 var
,无法将值设置为 None
使连接无效,并在再次建立数据库连接后将其设置为新值。
创建这种逻辑的功能方法是什么?我需要连接的静态值,以便只创建一个连接,并且我需要一种方法来检查该值是否过时。
1条答案
按热度按时间pbwdgjma1#
易变性通常是不可避免的,因为它是我们构建的系统的固有属性。然而,这并不意味着我们必须在代码中使用可变变量。
通常有两种主要方法可以处理涉及可变状态的情况:
将可变状态推送到程序外部的存储库中。
典型的例子是“标准”数据库(如果状态需要持久化)和内存存储(如果状态在程序生命周期内存在)。无论何时从这样的存储中获取值,都会将其视为不可变的值。易变性仍然存在,但不在程序中,这使其更容易推理。
有些人批评这种思维方式,说“你没有解决任何问题,你只是把它变成别人的问题”,事实上这是真的。我们让数据库为我们处理可变性。为什么不?这就是数据库的设计目的。此外,易变性的主要问题是关于它的推理,我们不会对数据库的内部实现进行推理。因此,将可变性从一个服务推到另一个服务,确实就像扔烫手山芋,但将其推到专门为其设计的外部系统是完全正确的。
然而,尽管如此,这对您的情况并没有帮助,因为将数据库连接对象存储在外部存储器中并不是很优雅。我要说的是第二点。
使用状态单子。
如果“monad”这个词给你带来了一些启示,那就假装我说了“使用”
State
“(其实这是个很简单的概念,不需要大字)。我将使用State
在cats库中可用,但它也存在于其他fp库中。State
是从某个现有状态到某个新状态和某个生成值的函数:通过从一个现有状态到一个新的状态,我们实现了“状态突变”。
例1:
下面是一些使用整数状态的代码,该状态将递增1,并在每次状态更改时生成一个字符串值:
这就是要点。
例2:
为了完整性,这里有一个更大的示例,它演示了一个与您类似的用例。
首先,让我们介绍一个简化的
CassandraConnection
(这只是为了以身作则;真实对象将来自cassandra库,因此我们自己的代码中不存在可变性)。我们应该如何定义国家?可变对象显然是
CassandraConnection
,用于理解的结果值可以是一个简单的String
.现在让我们定义一些函数来使用现有的
CassandraConnection
对象。最后,让我们在主程序中使用这些函数:
我知道这不是您可以复制/粘贴到项目中并使其正常工作的确切代码,但我想给出一个稍微更一般的答案,这可能会让其他读者更容易理解。我相信,只要有人玩弄一下,你就能把它塑造成你自己的解决方案。只要你的主程序是一个关于理解的
State
级别,您可以轻松地打开和关闭连接,并(重新)使用相同的连接对象。我们用这个解决方案到底取得了什么成果?为什么这比有一个可变的
CassandraConnection
价值?一件大事是我们实现了引用透明性,这就是为什么这个模式很好地适合于函数式编程范式,而标准的可变性却不适合。由于这个答案已经有点长了,我将向您介绍cats文档,它将更详细地解释整个过程,并演示使用cats的好处
State
非常好。