android 用于创建具有多个方法的类的设计模式,这些方法应按顺序执行

m0rkklqb  于 2023-01-03  发布在  Android
关注(0)|答案(2)|浏览(184)

我正在尝试创建一个模板类来测试文件室迁移。测试文件室迁移应该遵循的步骤如下。
1.在早期版本中创建数据库。
1.用户迁移助手迁移到下一版本。
1.插入一些数据。
1.验证数据的完整性。
现在我已经创建了一个类MigrationHelper,它相应地实现了所有这些方法。

class MigrationHelper {

 fun createDatabase(version : Int) : MigrationHelper{
       initialDatabase = migrationTestHelper.createDatabase(TEST_DB_NAME , version)
       return this
 }

 fun insertData(db : SupportSQLiteDatabase){
   ... 
 }

}

对于这个类,我目前使用的是builder方法,这样编写测试的开发人员就可以用一种干净易懂的方式调用方法。

@Test
    fun runMigration_78_79(){
        migrationHelper.setUp("test_db")
            .addTablesInvolved("packs")
            .createDatabaseWithData(78)
            .addMigrations(MIGRATION_77_78,MIGRATION_78_79)
            .runMigration(79)
            .cleanOut()

    }

但是由于builder模式,任何方法都可以按任何顺序调用。这对我的实现不好,因为有些方法必须按顺序调用。例如:可以在“addMigration”方法之前调用“runMigration”方法,因为要运行迁移,您需要添加所有涉及的迁移的数组。
对于这种情况,什么是最好的设计模式呢?我知道我可能过于复杂了,我可以用一堆方法创建类,然后单独调用它们。但是我希望有一个干净的方法。谢谢。

rqqzpn5f

rqqzpn5f1#

当您将所有内容放入一个构建器中时,构建器模式本身并没有帮助,但是您可以将方法拆分到不同的构建器中,以反映您当前所处的状态。当每个构建器只包含只能在相应状态下执行的操作时,不可能以错误的顺序调用操作。
例如,你可以有一个InitialBuilder,它有一个函数setUp,该函数返回一个EmptyDbBuilder,而EmptyDbBuilder又可能包含一个函数addTablesInvolved,返回一个DbWithTablesBuilder,等等。
这样,您就可以完全控制在不同情况下可以调用或不能调用的函数。

lnlaulya

lnlaulya2#

您的“builder模式”示例并不是真正的builder模式,它只是使用了链接的方法调用,而没有构建任何内容。
构建器模式实际上允许你以任何顺序提交调用,因为方法调用只收集参数,然后有一个最后的方法调用来执行整个集合。这个最后的方法调用将以正确的顺序执行工作。类似于下面的内容。这只是一个例子--我没有做过这样的房间测试,所以我的一些语法可能是错误的。

class MigrationHelper private constructor(val databaseName: String) {

  companion object {
    fun build(databaseName: String) = MigrationHelper(databaseName)
  }

  private var startingDatabaseVersion: Int? = null
  private val tables = mutableSetOf<String>()
  private val migrations = mutableSetOf<Migration>()
  private val migrationsToRun = mutableSetOf<Int>()

  fun createDatabase(version : Int): MigrationHelper {
    startingDatabaseVersion = version
    return this
  }

  fun addTablesInvolved(vararg tables: String): MigrationHelper {
    for (table in tables) this.tables += table
    return this
  }

  fun addMigrations(vararg migrations: Migration): MigrationHelper {
    for (migration in migrations) this.migrations += migration
    return this
  }

  fun runMigration(version: Int): MigrationHelper {
    migrationsToRun += version
    return this
  }

  fun execute() {
    val startingVersion = startingDatabaseVersion ?: 
      error("Missing initial version. Must call createDatabaseWithData() before execute()")

    migrationTestHelper.createDatabase(databaseName, startingVersion)
      .addMigrations(*migrations.toTypedArray())
      .build()
      .use {
        for (table in tables) {
          // add table to db
        }
        for (migration in migrationsToRun.sorted()) {
          // run migration
        }
      }
  }

}

用法:

MigrationHelper.build("test_db")
  .addTablesInvolved("packs")
  .createDatabaseWithData(78)
  .addMigrations(MIGRATION_77_78,MIGRATION_78_79)
  .runMigration(79)
  .execute()

// Everything between the first and last lines above can be entered in any order.

相关问题