首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >这是用Kotlin在类中实例化对象的好方法吗?

这是用Kotlin在类中实例化对象的好方法吗?
EN

Stack Overflow用户
提问于 2019-10-28 03:14:24
回答 5查看 1.2K关注 0票数 3

我总是在CameraX项目中找到代码,就像代码A一样。它使用类内的companion object中的对象创建实例。

如果我写同样的代码,我将使用代码B。

用Kotlin实例化类中的对象是一种很好的方法吗?A代码比B代码好吗?

顺便说一下,我不认为“每个片段类都必须有一个空的构造函数”。请考虑一个普通的类而不是片段类,好吗?

码A

代码语言:javascript
代码运行次数:0
运行
复制
class UIFragmentPhoto internal constructor() : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?) = ImageView(context)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val args = arguments ?: return
        val resource = args.getString(FILE_NAME_KEY)?.let { File(it) } ?: R.drawable.ic_photo
        Glide.with(view).load(resource).into(view as ImageView)
    }

    companion object {
        private const val FILE_NAME_KEY = "file_name"

        fun create(image: File) = UIFragmentPhoto().apply {
            arguments = Bundle().apply {
                putString(FILE_NAME_KEY, image.absolutePath)
            }
        }
    }
}

调用A

代码语言:javascript
代码运行次数:0
运行
复制
override fun getItem(position: Int): Fragment = UIFragmentPhoto.create(mediaList[position])

码B(修改)

代码语言:javascript
代码运行次数:0
运行
复制
class UIFragmentPhoto internal constructor() : Fragment() {
    val FILE_NAME_KEY = "file_name"

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?) = ImageView(context)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val args = arguments ?: return
        val resource = args.getString(FILE_NAME_KEY)?.let { File(it) } ?: R.drawable.ic_photo
        Glide.with(view).load(resource).into(view as ImageView)
    }


    constructor(image: File):this(){
        arguments = Bundle().apply {
            putString(FILE_NAME_KEY, image.absolutePath)
        }
    }

}

调用B(修改)

代码语言:javascript
代码运行次数:0
运行
复制
override fun getItem(position: Int): Fragment = UIFragmentPhoto(mediaList[position])
EN

回答 5

Stack Overflow用户

发布于 2019-11-01 09:56:22

Fragment的情况下:

根据定义默认构造函数的Fragment类在android.googlesource.com上的源代码,我们看到:

每个片段都必须有一个空的构造函数,因此可以在恢复其活动的状态时实例化它。强烈建议子类没有带有参数的其他构造函数,因为当片段被重新实例化时不会调用这些构造函数;相反,参数可以由调用方提供setArguments,然后由带有getArguments.Applications的片段检索,通常不应该实现构造函数。而更喜欢onAttach(上下文)。这是应用程序代码在准备使用片段的地方运行的第一个地方--片段实际上与其上下文相关联的位置。一些应用程序也可能希望实现onInflate来从布局资源中检索属性,但请注意,这是在附加片段时发生的。

鉴于上述原因,在非默认构造函数中添加Fragment是禁止的!

之后,使用setArgumentsgetArguments方法是避免添加额外构造函数的另一种方法。有问题的代码B,同时使用这两种方法。您应该使用其中之一,比如代码A。(因为当您将参数传递给构造函数时,可以在类中访问它。所以不需要[set/get]Arguments模式)

但是,如果我们想不使用参数重写代码B (免责声明:我强调这种方法不是真的),我们可以这样做:

代码语言:javascript
代码运行次数:0
运行
复制
class UIFragmentPhoto internal constructor(private val image: File?) : Fragment() {

    constructor() : this(null)

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?) = ImageView(context)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val resource = image ?: R.drawable.ic_photo
        Glide.with(view).load(resource).into(view as ImageView)
    }

}

一般而言:

我们都知道,对象是通过调用Java/Kotlin中类的构造函数方法创建的。例如:

代码语言:javascript
代码运行次数:0
运行
复制
val obj = MyClass()

当您想要创建一个对象时,不需要将构造函数调用包装在另一个函数中,除非必须根据程序的性质更改对象的性质。因为它会导致额外的函数调用来创建一个没有任何优势的对象。

在根据程序性质变化对象的情况下,必须借助创造性的设计模式,提供更通用、更灵活的方法(如:工厂方法、抽象工厂模式等)。

结论:

  1. 当您处理从Fragment类创建对象时,应该使用代码--样式。(因为android.googlesource.com描述的原因)
  2. 当您处理从non-**Fragment类创建对象时,最好使用代码B**样式。(因为避免了没有优势的额外函数调用)
票数 4
EN

Stack Overflow用户

发布于 2019-10-28 03:26:27

不,这是低效的。代码B要求实例化片段的丢弃副本,这样就可以调用工厂方法来创建所需的实际片段。

票数 0
EN

Stack Overflow用户

发布于 2019-10-28 03:46:36

是用Kotlin在类中实例对象的好方法吗?

不怎么有意思。而且,这与Kotlin无关,它是一个语言不可知论的https://www.google.com/search?q=static%20factory%20method

如果以(B)方式初始化片段,则有三个问题:

1)很容易忘记在您的实例中调用“创建”:

代码语言:javascript
代码运行次数:0
运行
复制
override fun getItem(position: Int): Fragment = UIFragmentPhoto() // Oops - bug

2)如果将create作为实例方法,则可以在现有片段上反复调用它:

代码语言:javascript
代码运行次数:0
运行
复制
fun someFunction() {
    UIFragmentPhoto fragment = getExistingFragment()
    fragment.create() // Oops - just overwrote the fragment state
}

3)拥有一个“创建”已经创建的实例的方法只是让人困惑,也是初始化片段的一种非标准方法。这种静态/伴生方式的要点是,您有一个函数,它的任务是创建和初始化对象。

工厂方法还为您提供了在返回对象之前执行错误处理/验证的灵活性,并使您有机会创建一个完全不同的对象类型,该对象类型扩展/实现返回类型(如果您选择的话):

代码语言:javascript
代码运行次数:0
运行
复制
companion object {
    fun create(arg: Int): UIFragmentPhoto {
        if (arg == 0) throw IllegalStateException("Wasn't expecting 0!")
        if (arg == 1) return FragmentThatExtendsUIFragmentPhoto()
        if (arg == 2) return UIFragmentPhoto()
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58585384

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档