目录
系列文章目录
Kotlin学习笔记三:联系人列表
前言
上期主要讲了联系人列表这一个demo,接下来咱们在用面向对象的方法来完善我们的项目。主要涉及到的知识点有jar包的引用,单例对象,伴生对象,以及使用的各种函数。
一、前期准备
项目UML类图如下(会与项目有所不同):
二、主要代码
1.操作见面(OperationInterface类)
代码如下(示例):
import InputOperation.inputInt
import InputOperation.inputPersonName
import java.util.*
/**
* 第1步.显示操作界面
* 创建一个单例
* 这种设计使得操作界面的逻辑和显示分离,使得代码更清晰、可维护性更强。
*/
//这里 OperationInterface 类的构造函数是私有的
// (private constructor())这意味着这个类不能在类的外部被直接实例化。
// 只能在类的内部创建实例。
class OperationInterface private constructor(){
//伴生对象 (companion object) 是 Kotlin 的一种特性,它允许在类内部定义一个对象,
// 这个对象与类相关联,并且可以像静态成员一样被访问。
// 在 companion object 内部定义的成员可以直接通过类名访问。
companion object{
//在伴生对象中,定义了一个名为 instance 的 val,其类型是 OperationInterface。
// instance 使用 by lazy 进行初始化,这意味着 OperationInterface 实例的创建是延迟的
// 只有在第一次访问 instance 时才会创建实例。
// 这种方式确保了线程安全,并且在多线程环境下也只会创建一个实例。
val instance:OperationInterface by lazy {
OperationInterface()
}
}
//显示菜单
fun showMenu(){
println("----------------------")
println("1. 添加好友")
println("2. 删除好友")
println("3. 显示列表")
println("4. 退出")
println("----------------------")
}
//选择操作
//创建操作的类型
fun choose() {
//因为选择的方法不同,每个对应相应的函数
when (val interfaceInput = inputInt()) {
3 -> ContactExt.instance.show()
4 -> ContactExt.instance.exit()
else -> {
val name = inputPersonName()
when (interfaceInput) {
1 -> ContactExt.instance.add(name)
2 -> ContactExt.instance.delete(name)
}
}
}
}
}
2.联系人管理类(ContactExt类)
代码如下(示例):
import kotlin.system.exitProcess
/**
* 第二步.联系人管理类
* 存储联系人
* 与外界交互
*/
class ContactExt private constructor(){
//创建单例,只有一个
companion object {
/**
* 三种方法。。。。。。6:05
* by lazy 懒加载
* 定义时不加载,使用时才加载
* 只会被加载一次
*/
val instance: ContactExt by lazy {
ContactExt()
}
}
//容器保存所有联系人
private val sectionList:ArrayList<Section> = ArrayList()
//保存每个小组的组名
private val titles: ArrayList<Char> = arrayListOf()
//两种创建 ArrayList 实例的方式稍有不同,但在功能上是等效的
//添加好友
fun add(name:String){
addFriend(Person().apply { this.name = name })
}
private fun addFriend(person: Person) {
//判断有没有自己的小组
if (titles.contains(person.title)){
//找到section
for (section in sectionList){
if (section.title == person.title){
section.add(person)
break
}
}
}else{
val section = Section(person.title, arrayListOf(person))
sectionList.add(section)
titles.add(person.title)
}
//对section排序
sectionList.sortBy {
it.title
}
}
fun delete(name:String) {
val person = Person().apply { this.name = name }
//判断组名有没有
if (titles.contains(person.title)) {
for (section in sectionList) {
//找到要删除的人
if (section.title == person.title) {
section.delete(person.name)
//若该小组没人,则删除标题
if (section.friendList.isEmpty()) {
sectionList.remove(section)
titles.remove(person.title)
}
break
}
}
}
}
fun show(){
sectionList.forEach { it.show() }
}
fun exit(){
exitProcess(1)
}
}
3.创建小组列表(Section)
/**
* 第3步.创建小组列表
*/
class Section(val title:Char,val friendList:ArrayList<Person>) {
fun add(person:Person){
friendList.add(person)
//下一步对person排序
friendList.sortWith(person)
}
fun delete(name:String){
for (p in friendList){
if (p.name == name){
friendList.remove(p)
break
}
}
}
fun show(){
println(title)
friendList.forEach {
println(it)
}
}
}
4.创建联系人
/**
* 第四步.创建person类
* 好友类
* 基本信息和比较方法
*/
class Person : Comparator<Person> {
//先初始化
//在重写方法,存储外部值
var name:String = ""
set(value) {
field = value
//定义一个object类来
pinyin = PinyinUtils.toPinyin(value,PinyinType.WORD_FIRST_UPPERCASE)
}
var pinyin:String = ""
set(value) {
field = value
title = pinyin.first().uppercaseChar()
nameAbbr = pinyin.filter { it in 'A'..'Z' }
}
var title:Char = '0'
var nameAbbr:String = "" //名字首字母缩写
override fun toString(): String {
return "$name $pinyin"
}
//自己制定比较的方式 比较复杂 或者封装
override fun compare(o1: Person?, o2: Person?): Int {
if (o1 == null && o2 == null) return 0
if (o1 != null && o2 == null) return 1
if (o1 == null && o2 != null) return -1
//先比较缩略字母
if (o1!!.nameAbbr != o2!!.nameAbbr)
return o1.nameAbbr.compareTo(o2.nameAbbr)
//缩略名相同了 直接比全名
return o1.pinyin.compareTo(o2.pinyin)
}
}
5.创建单例对象(PinyinUtils)
import net.sourceforge.pinyin4j.PinyinHelper
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType
/**
* 第五步.
* 转化大小写
* object 关键字用于创建单例对象
* 它是一种特殊的类,只能有一个实例存在
* 并且可以直接访问其内部的方法和属性
* 将中文转化为拼音
* 接收中文名
* 返回完整的拼音
*/
object PinyinUtils {
fun toPinyin(name:String, type: PinyinType):String{
val format = HanyuPinyinOutputFormat().also {
it.caseType = if (type == PinyinType.ALL_UPPERCASE)
HanyuPinyinCaseType.UPPERCASE
else
HanyuPinyinCaseType.LOWERCASE
it.toneType = HanyuPinyinToneType.WITHOUT_TONE
}
//遍历name中的每一个中文汉字
var wholeName: String = ""
for (word in name) {
//将这个中文转化为拼音
val pinyin = PinyinHelper.toHanyuPinyinStringArray(word, format).first()
if (type == PinyinType.WORD_FIRST_UPPERCASE) {
val formattedPy = pinyin.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
wholeName += formattedPy
}else wholeName += pinyin
}
return wholeName
}
}
6.创建枚举类型(PinyinType)
/**
* 第六步.
* 创建枚举类型
* 枚举类型是一种特殊的数据类型,用于定义一组固定的命名常量
*/
enum class PinyinType {
ALL_LOWERCASE, //全部小写
ALL_UPPERCASE, //全部大写
WORD_FIRST_UPPERCASE //首字母大写
}
总结
通过类与对象的思想,我们可以把事物拆分成多个对象,每块功能各司其职,但又互相关联,并且使我们可以简化程序的复杂度、提高代码的可维护性和可复用性