Создание компоновщика с некоторыми константами и другими переменными - PullRequest
4 голосов
/ 10 февраля 2020
kotlin 1.3.61

У меня есть следующий класс, и я не уверен, что это лучший дизайн для создания строителя. В основном, продажи и продукт будут иметь разные константы для иконки и фона. Но название и описание могут быть изменены. Могут быть добавлены другие константы, т.е. технические. Поэтому пользователю этого класса не нужно беспокоиться о том, как создаются эти константы.

Но название и адрес должны быть предоставлены за пределами класса. При создании моего конструктора я использовал copy для обновления заголовка и описания. И не уверен, что это лучший способ сделать это?

class Marketing {
    data class Model(
        val title: String = "",
        val description: String = "",
        val icon: Int,
        val background: Int)

    class Builder() {
        private var title: String = ""
        private var description: String = ""

        private val PRODUCT = Model(
            icon = 111111,
            background = 333333)

        private val SALES = Model(
            icon = 222222,
            background = 444444)

        fun title(title: String): Builder {
            this.title = title
            return this
        }

        fun description(description: String): Builder {
            this.description = description
            return this
        }

        fun buildProduct(): Model {
            return PRODUCT.copy(title = title, description = description)
        }

        fun buildSales(): Model {
            return SALES.copy(title = title, description = description)
        }
    }
}

И я использую это так:

val product = Marketing.Builder()
    .description("this is the description of the product")
    .title("this is the title of the product")
    .buildProduct()

val sales = Marketing.Builder()
    .description("this is the description of the sales")
    .title("this is the title of the sales")
    .buildSales()

Как видите, легко создавать разные продукты позвонив соответствующему застройщику, например buildProduct() и buildSales()

Большое спасибо за любые предложения по улучшению

Ответы [ 3 ]

7 голосов
/ 12 февраля 2020

Вы можете рассмотреть возможность использования sealed классов, таких как:

sealed class Model(
    open val title: String,
    open val description: String,
    val icon: Int,
    val background: Int
) {
  data class Product(override val title: String, override val description: String) :
      Model(
          title,
          description,
          111111,
          333333)

  data class Sales(override val title: String, override val description: String) :
      Model(
          title,
          description,
          111111,
          333333)
}

Таким образом:

  • У вас есть унифицированные типы (то есть один и тот же суперкласс, поэтому вы можете передавать их с одинаковым типом (Model))
  • Вы можете иметь различные и / или общие функции для всех из них

Преимущества:

Вы можете передать экземпляры как Model и обрабатывают все экземпляры одинаково и / или проверяют их в предложении when для правильного типа для действия (для которого не требуется ветвь else, если используется в качестве выражения):

fun showModel(model: Model){
    title.text = model.title
}

или вы можете сделать:

fun doSomething(model: Model) = when (model) {
    is Product -> Unit
    is Sales -> Unit
}

Вы можете узнать больше о закрытых классах здесь .

4 голосов
/ 10 февраля 2020

Честно говоря, я не понимаю, почему это не просто два метода:

fun buildProduct(title: String, description: String): Model {
    return Model(icon = 111111, background = 333333, title = title, description = description)
}

fun buildSales(title: String, description: String): Model {
    return Model(icon = 222222, background = 444444, title = title, description = description)
}

Или, может быть,

class Builder(private val title: String, private val description: String) {
    fun buildProduct(): Model {
        return Model(icon = 111111, background = 333333, title = title, description = description)
    }

    fun buildSales(): Model {
        return Model(icon = 222222, background = 444444, title = title, description = description)
    }
}

Если вы хотите, чтобы title и description были всегда именованный, он не выглядит как Model с пустым заголовком, а описание действительно полезно (не так ли?), поэтому вместо того, чтобы задавать их по умолчанию, я бы добавил дополнительный класс

data class Model(
    val title: String,
    val description: String,
    val icon: Int,
    val background: Int)

class Builder() {
    data class ModelTemplate(val icon: Int, val background: Int) {
        // optionally check that title and description aren't empty, or are valid in some other way
        fun build(title: String, description: String) = Model(icon, background, title, description)
    }

    private val product = ModelTemplate(icon = 111111, background = 333333)
    private val sales = ModelTemplate(icon = 222222, background = 444444)

    private var title: String = ""
    private var description: String = ""

    fun title(title: String): Builder {
        this.title = title
        return this
    }

    fun description(description: String): Builder {
        this.description = description
        return this
    }

    fun buildProduct(): Model {
        return product.build(title = title, description = description)
    }

    fun buildSales(): Model {
        return sales.build(title = title, description = description)
    }
}
2 голосов
/ 14 февраля 2020

Я бы хотел сказать, что использование одного компоновщика небезопасно для построения нескольких типов. Было бы лучше разделить его на определенные c классы, возможно, с некоторым общим базовым классом. Итак, мой ответ:

Классы моделей

open class BaseModel(val icon: Int, val background: Int)
class ProductModel(val title: String, val description: String, icon: Int, background: Int) : BaseModel(icon, background)
class SalesModel(val title: String, val description: String, icon: Int, background: Int) : BaseModel(icon, background)

Строители

abstract class BaseBuilder<T : BaseModel> {
    abstract var icon: Int
    abstract var background: Int

    abstract fun build(): T
}

class ProductBuilder : BaseBuilder<ProductModel>() {
    override var icon = 222222
    override var background = 444444
    var title = ""
    var description = ""

    override fun build() = ProductModel(title, description, icon, background)
}

class SalesBuilder : BaseBuilder<SalesModel>() {
    override var icon = 111111
    override var background = 333333
    var title = ""
    var description = ""

    override fun build() = SalesModel(title, description, icon, background)
}

И, наконец, Маркетинговый класс

class Marketing {
    companion object {
        fun buildProduct(filler: ProductBuilder.() -> Unit) : ProductModel {
            return ProductBuilder().run {
                filler()
                build()
            }
        }
        fun buildSales(filler: SalesBuilder.() -> Unit) : SalesModel {
            return SalesBuilder().run {
                filler()
                build()
            }
        }
    }
}

Таким образом, вы можете легко и безопасно создавать модели:

val product = Marketing.buildProduct {
    title = "title"
    description = "descr"
}

Обязательное поле

Если вы хотите сделать какое-либо свойство неизменяемым, вы можете заменить его из свойства var в конструктор на val. Пример для title свойство:

Builder

class ProductBuilder(val title: String) : BaseBuilder<ProductModel>() {
    override var icon = 111111
    override var background = 333333

    var description = ""

    override fun build() = ProductModel(title, description, icon, background)
}

Builder вызывает

fun buildProduct(title: String, filler: ProductBuilder.() -> Unit) : ProductModel {
    return ProductBuilder(title).run {
        filler()
        build()
    }
}

Использование

val product = Marketing.buildProduct("title") {
    //title = "title" - this line wouldn't be compiled anymore
    description = "descr"
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...