分享:
kotlin学习练习网站-https://github.com/dbacinski/Design-Patterns-In-Kotlin
kotlin资料网站-
设计模式网站-http://www.runoob.com/design-pattern/decorator-pattern.html
引言:
设计模式的本质是让我们更好的运用面向对象有点,应对项目的后期的需求变更和变化
那么在学习和使用kotlin中结合以往的设计模式会怎么样呢?
以下不是抛开实际需求而是实战中运用到设计模式
主页目录:
策略模式
单例模式
工厂模式
代理模式
观察者模式
建造者模式
适配器模式
责任链模式
命令解释器模式
装饰模式
外观模式
状态模式
过滤器模式
访问者模式
策略模式Strategy
功能:为不同的字符串处理提供不同的算法
import java.text.DecimalFormat
import java.util.regex.Pattern
interface ValueTransform {
@Throws(NumberFormatException::class)
fun transform(str:String?):String?
}
inline fun String.vt(t:ValueTransform): String?{
return t.transform(this)
}
class NumberFromat(val len:Int):ValueTransform{
override fun transform(str: String?): String? {
return String.format("%0${len}d",Integer.valueOf(str))
}
}
class TimerNumberFromat(val len:Int):ValueTransform{
override fun transform(str: String?): String? {
var sb=StringBuffer();
val pattern = Pattern.compile("[\\d]++|[\\D]++")
val matcher = pattern.matcher(str)
fun isNumber(str: String):Boolean=Pattern.compile("[0-9]*").matcher(str).matches()
while (matcher.find()) {
var value=matcher.group()
when(isNumber(value)){
true -> sb.append(value.vt(NumberFromat(2)))
else -> sb.append(value)
}
}
return sb.toString()
}
}
class GoldFormat(val len:Int):ValueTransform{
override fun transform(str: String?): String? {
var sb=StringBuffer(".")
if(len<=0)
{
return str?.toDouble()?.toInt().toString()
}
for(i in 0..len-1) {
sb.append("0")
}
return DecimalFormat(sb.toString()).format(str?.toDouble())
}
}
fun main(args: Array<String>) {
println("9->"+("9".vt(NumberFromat(2))))
println("9->"+("9".vt(GoldFormat(2))))
println("1989-9-1 1:4:15->"+("1989-9-1 1:4:15".vt(TimerNumberFromat(2))));
}
单例模式Singleton
object PrinterDriver {
init {
println("Initializing with object: $this")
}
fun print() = println("Printing with object: $this")
}
fun main(args: Array<String>) {
println("Start")
PrinterDriver.print()
PrinterDriver.print()
}
工厂模式Factory
功能:减少项目变化所造成的影响
/**抽象工厂*/
interface Plant
class OrangePlant : Plant
class ApplePlant : Plant
abstract class PlantFactory {
abstract fun makePlant(): Plant
companion object {
inline fun <reified T : Plant> createFactory(): PlantFactory = when (T::class) {
OrangePlant::class -> OrangeFactory()
ApplePlant::class -> AppleFactory()
else -> throw IllegalArgumentException() as Throwable
}
}
}
class AppleFactory : PlantFactory() {
override fun makePlant(): Plant = ApplePlant()
}
class OrangeFactory : PlantFactory() {
override fun makePlant(): Plant = OrangePlant()
}
fun main(args: Array<String>) {
val plantFactory = PlantFactory.createFactory<OrangePlant>()
val plant = plantFactory.makePlant()
println("Created plant: $plant")
}
代理模式ProtectionProxy
功能:通过代理禁止访问文件的密码
interface File {
fun read(name: String)
}
class NormalFile : File {
override fun read(name: String) = println("Reading file: $name")
}
//Proxy:
class SecuredFile : File {
val normalFile = NormalFile()
var password: String = ""
override fun read(name: String) {
if (password == "secret") {
println("Password is correct: $password")
normalFile.read(name)
} else {
println("Incorrect password. Access denied!")
}
}
}
fun main(args: Array<String>) {
val securedFile = SecuredFile()
securedFile.read("readme.md")
securedFile.password = "secret"
securedFile.read("readme.md")
}
观察者模式Observer
功能:文本框内容变化时通知其他监听器发生变化
import kotlin.properties.Delegates
interface TextChangedListener {
fun onTextChanged(newText: String)
}
class PrintingTextChangedListener : TextChangedListener {
override fun onTextChanged(newText: String) = println("Text is changed to: $newText")
}
class TextView {
var listener: TextChangedListener? = null
var text: String by Delegates.observable("") { prop, old, new ->
listener?.onTextChanged(new)
}
}
fun main(args: Array<String>) {
val textView = TextView()
textView.listener = PrintingTextChangedListener()
textView.text = "Lorem ipsum"
textView.text = "dolor sit amet"
}
建造者模式Build
功能:创建一个可自定义各种样式的对话框
import java.io.File
// Let's assume that Dialog class is provided by external library.
// We have only access to Dialog public interface which cannot be changed.
/**建造*/
class Dialog() {
fun showTitle() = println("showing title")
fun setTitle(text: String) = println("setting title text $text")
fun setTitleColor(color: String) = println("setting title color $color")
fun showMessage() = println("showing message")
fun setMessage(text: String) = println("setting message $text")
fun setMessageColor(color: String) = println("setting message color $color")
fun showImage(bitmapBytes: ByteArray) = println("showing image with size ${bitmapBytes.size}")
fun show() = println("showing dialog $this")
}
//Builder:
class DialogBuilder() {
constructor(init: DialogBuilder.() -> Unit) : this() {
init()
}
private var titleHolder: TextView? = null
private var messageHolder: TextView? = null
private var imageHolder: File? = null
fun title(init: TextView.() -> Unit) {
titleHolder = TextView().apply { init() }
}
fun message(init: TextView.() -> Unit) {
messageHolder = TextView().apply { init() }
}
fun image(init: () -> File) {
imageHolder = init()
}
fun build(): Dialog {
val dialog = Dialog()
titleHolder?.apply {
dialog.setTitle(text)
dialog.setTitleColor(color)
dialog.showTitle()
}
messageHolder?.apply {
dialog.setMessage(text)
dialog.setMessageColor(color)
dialog.showMessage()
}
imageHolder?.apply {
dialog.showImage(readBytes())
}
return dialog
}
class TextView {
var text: String = ""
var color: String = "#00000"
}
}
//Function that creates dialog builder and builds Dialog
fun dialog(init: DialogBuilder.() -> Unit): Dialog {
return DialogBuilder(init).build()
}
fun main(args: Array<String>) {
val dialog: Dialog = dialog {
title {
text = "Dialog Title"
}
message {
text = "Dialog Message"
color = "#333333"
}
image {
File.createTempFile("image", "jpg")
}
}
dialog.show()
}
适配器模式Adapter
/**适配器模式器模式-将开氏温度和摄氏温度换算*/
interface Temperature {
var temperature: Double
}
class CelsiusTemperature(override var temperature: Double) : Temperature
class FahrenheitTemperature(var celsiusTemperature: CelsiusTemperature) : Temperature {
override var temperature: Double
get() = convertCelsiusToFahrenheit(celsiusTemperature.temperature)
set(temperatureInF) {
celsiusTemperature.temperature = convertFahrenheitToCelsius(temperatureInF)
}
private fun convertFahrenheitToCelsius(f: Double): Double = (f - 32) * 5 / 9
private fun convertCelsiusToFahrenheit(c: Double): Double = (c * 9 / 5) + 32
}
fun main(args: Array<String>) {
val celsiusTemperature = CelsiusTemperature(0.0)
val fahrenheitTemperature = FahrenheitTemperature(celsiusTemperature)
celsiusTemperature.temperature = 36.6
println("${celsiusTemperature.temperature} C -> ${fahrenheitTemperature.temperature} F")
fahrenheitTemperature.temperature = 100.0
println("${fahrenheitTemperature.temperature} F -> ${celsiusTemperature.temperature} C")
}
责任链模式ChainOfResponsibility
功能:根据url来定义(跳转 打开或者自定义)功能 类似击鼓传花
enum class SchemeAction(var host: String, var action: (Map<String, String>) -> Unit) {
OrderUI("scheme://order", {
println("start order acitvity - parm=${it["id"]}")
}),
Evaluate("scheme://evaluate", {
println("start evaluate acitvity ${it["id"]}")
}),
web("", {
println("start web")
});
fun isMatching(url: String): SchemeAction? = when (true) {
url.indexOf(host) == 0 -> this
else -> null;
}
companion object {
fun matching(url: String) {
SchemeAction.values().forEach {
var scheme = it.isMatching(url)
scheme?.action?.invoke(paramToMap(url))
scheme?.run { return }
}
}
fun paramToMap(url: String): Map<String, String> = HashMap<String, String>().apply {
var arr=url.split("\\?".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
if(arr.size==2){
arr[1].split("&".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray().forEach {
var parm=it.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
if(parm.size==2)this[parm[0]]=parm[1]
}
}
}
}
}
fun main(args: Array<String>) {
SchemeAction.matching("scheme://evaluate?id=5")
SchemeAction.matching("http://www.baidu.com")
}
命令解释器模式CommandandInterpreterPattern
功能:给产品或者其他设计定义一种开放简单脚本用来编写剧情
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledThreadPoolExecutor
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantLock
class TimeWait(val time: Long) : Runnable {
companion object {
val poolExecutor: ScheduledThreadPoolExecutor = ScheduledThreadPoolExecutor(10)
}
var keepOn = false;
var lock = ReentrantLock()
var condition = lock.newCondition()
override fun run() {
println("等待:" + time)
poolExecutor.schedule({
lock.lock()
keepOn = true
condition.signalAll();
lock.unlock()
}, time, TimeUnit.MILLISECONDS)
while (!keepOn) {
lock.lock()
condition.await()
lock.unlock()
}
}
}
interface Interpreter {
fun interpreter(command: String, commandArr: List<String>): Runnable?
}
class SkillInterpreter : Interpreter {
override fun interpreter(command: String, arr: List<String>): Runnable? {
if (arr[0].equals("skill")) {
return when (arr[2]) {
"eat" -> Runnable { println("${arr[1]} skill ${arr[2]} (O ^ ~ ^ O)") }
"ultimate" -> Runnable { println("${arr[1]} skill ${arr[2]}(╯‵□′)╯︵┴─┴") }
else -> Runnable { }
}
}
return null
}
}
class MoveInterpreter : Interpreter {
override fun interpreter(command: String, arr: List<String>): Runnable? {
if (arr[0].equals("move")) {
return when (arr[3]) {
"right" -> Runnable { println("${arr[1]} is >>move>> ${arr[2]}") }
"left" -> Runnable { println("${arr[1]} is <<move<< ${arr[2]}") }
else -> Runnable { }
}
}
return null
}
}
class TimeInterpreter : Interpreter {
override fun interpreter(command: String, arr: List<String>): Runnable? {
if (arr[0].equals("wait")) {
return TimeWait(arr[1].toLong())
}
return null
}
}
object ScriptProcessor {
var service = Executors.newSingleThreadExecutor();
var queueAction = LinkedList<Runnable>()
var scripts= arrayListOf<Interpreter>()
fun load(clazz:Class<out Interpreter>):ScriptProcessor{
scripts.add(clazz.newInstance())
return this
}
fun addAction(actuin: String): ScriptProcessor = apply {
addAction(change(actuin))
}
fun addAction(actuin: Runnable): ScriptProcessor = apply { queueAction.add(actuin) }
private fun change(action: String): Runnable {
try {
var arr = action.split(" ")
for(script in scripts) {script.interpreter(action, arr)?.apply{ return this }}
return Runnable { println("无效脚本:${action}") }
} catch (e: Exception) {
return Runnable { println("错误脚本:${action}") }
}
}
fun start(): ScriptProcessor = apply {
while (!queueAction.isEmpty()) {
service.submit(queueAction.pollFirst())
}
}
}
fun main(args: Array<String>) {
ScriptProcessor
.load(SkillInterpreter::class.java)
.load(MoveInterpreter::class.java)
.load(TimeInterpreter::class.java)
.addAction("skill k eat")
.addAction("wait 2000")
.addAction("wait ^%$%#$%")
.addAction("move k 5 right")
.addAction("wait 2500")
.addAction("mov k 5 left")//<-错误脚本
.addAction("wait 1000")
.addAction("move k 5 left")
.addAction("wait 1000")
.addAction("skill k ultimate")
.start()
}
输入结果
等待:2000
错误脚本:wait ^%%
k is >>move>> 5
等待:2500
无效脚本:mov k 5 left
等待:1000
k is <<move<< 5
等待:1000
k skill ultimate(╯‵□′)╯︵┴─┴
装饰者模式Decirator
功能:用类的方式创建html标签
类似的例子比如文字有颜色有粗体有斜体
饮料有冰 热 加糖 加椰果等等需求
这种需要大量组合的类
open class TextBlock
{
constructor(){}
constructor(str:String){content=str}
constructor(block:TextBlock)
{
nextBlock=block
}
var content: String?=null
var nextBlock:TextBlock?=null
open fun outPrintln():String{
return content?:"";
}
open fun link(textBlock: TextBlock):TextBlock{
textBlock.nextBlock=this
return textBlock
}
}
class ColorTextBlock:TextBlock
{
constructor(color:String){}
constructor(color:String,block:TextBlock){nextBlock=block}
override fun outPrintln():String{
return "<font color='#FF0000'>${nextBlock?.outPrintln()}</font>";
}
}
class StrongTextBlock:TextBlock
{
constructor(){}
constructor(block:TextBlock){nextBlock=block}
override fun outPrintln():String{
return "<strong>${nextBlock?.outPrintln()?:""}</strong>";
}
}
class SmallTextBlock:TextBlock
{
constructor(){}
constructor(block:TextBlock){nextBlock=block}
override fun outPrintln():String{
return "<small>${nextBlock?.outPrintln()}</small>";
}
}
fun main(args: Array<String>) {
ColorTextBlock("#FF0000",SmallTextBlock(TextBlock("文字"))).run { outPrintln() }
//简写
TextBlock("文字")
.link(SmallTextBlock())
.link(StrongTextBlock())
.link(ColorTextBlock("#FF0000"))
.run { outPrintln() }
}
外观模式Facade
功能:包装一层,将原本不同的很复杂的接口(支付宝sdk和微信sdk)统一成一种
import SimplePay.SimplePayListen
import SimplePay.pay
import java.util.*
class AliPaySdk{
interface AliPayListen{
fun alipayStatusListn(code:Int)
}
fun pay(gold:String,listen:AliPayListen){
listen.alipayStatusListn(0)
}
}
class WeixinPaySdk{
interface WeixinPayListen{
fun alipayStatusListn(errCode:String)
}
fun pay(gold:String,listen:WeixinPayListen){
listen.alipayStatusListn("susscess")
}
}
object SimplePay
{
const val PAY_TYPE_ALI=1
const val PAY_TYPE_WEIXIN=2
var aliPay=AliPaySdk()
var weixinPay=WeixinPaySdk();
interface SimplePayListen{
fun alipayStatusListn(payType:Int,errorCode:Int,message:String)
}
fun pay(payType:Int,gold:Double,listen:SimplePayListen){
when(payType){
PAY_TYPE_ALI->{
AliPaySdk().pay(gold.toString(),object:AliPaySdk.AliPayListen{
override fun alipayStatusListn(code: Int) {
var message:String=when(code)
{
0->"成功"
else->"失败"
}
listen.alipayStatusListn(PAY_TYPE_ALI,code,message)
}
})
}
PAY_TYPE_WEIXIN->{
WeixinPaySdk().pay(gold.toString(),object:WeixinPaySdk.WeixinPayListen{
override fun alipayStatusListn(errCode: String) {
var code=0
var message:String=when(errCode)
{
"susscess"->{"成功"}
else->{code=2;"失败"}
}
listen.alipayStatusListn(PAY_TYPE_ALI,code,message)
}
})
}
else->{
throw RuntimeException("no pay method")
}
}
}
}
fun main(args: Array<String>) {
SimplePay.pay(SimplePay.PAY_TYPE_ALI,1.0, object:SimplePayListen{
override fun alipayStatusListn(payType: Int, errorCode: Int, message: String) {
println("error code:${errorCode} message:${message}")
}
})
}
状态模式模式State
功能:为每一种状态定义不同的显示和点击事件
class Order{
var subscribeState:State = State(1,{println("ui->subscribeState")},{println("onclick->subscribeState")})
var payState:State = State(2,{println("show state->payState") },{println("onclick->payState") })
var finishState:State = State(3,{ println("show state->finishState")},{ println("onclick->finishState") })
var status:State=subscribeState
inner class State(val status:Int,val onRefreshUI:()->Unit,val onClick:()->Unit)
fun refreshUI(){
println("refreshUI")
status.onRefreshUI.invoke()
}
fun onClick(){
println("onClick")
status.onClick.invoke()
}
}
fun main(arr:Array<String>){
var order=Order()
order.status=order.finishState
order.refreshUI()
order.onClick()
}
过滤器模式Filter
为不同的人群筛选复杂的贷款套餐业务
import java.util.*
inline fun <reified T> orFilter(vararg args: (t:T)->Boolean): (t:T)->Boolean = { t: T->
var isCheck = false;
args.forEach { isCheck = it.invoke(t)||isCheck }
isCheck
}
inline fun <reified T> andFilter(vararg args: (t:T)->Boolean): (t:T)->Boolean = {t: T->
var isCheck = true;
args.forEach { isCheck = it.invoke(t)&&isCheck}
isCheck
}
inline fun <reified T> filter(list: List<T>, vararg arr:(t:T)->Boolean): List<T> {
var iterator = list.listIterator()
var resultList = arrayListOf<T>()
while (iterator.hasNext()) {
var value = iterator.next()
var isCheck = true;
for (filter in arr) {
isCheck = filter.invoke(value)
if (!isCheck) {
break
}
}
if (isCheck) {
resultList.add(value)
}
}
return resultList
}
data class Person(val id: Int, val name: String, val sex: Int, val loan: Int)
var manFilter = {t:Person->t.sex == 1}
var womenFilter = {t:Person->t.sex == 2}
var loan5Filter = {t:Person->t.loan>=5}
var loan6Filter = {t:Person->t.loan>=6}
var idFilter = {t:Person->t.id<=5}
//查询前5幸运客户或者资金大于5的男性
var planA=orFilter(andFilter(manFilter, loan5Filter), idFilter)
//查询资金大于等于5并且是男性 或者资金大于等于6的女性
var planB=andFilter(orFilter(manFilter, loan5Filter), orFilter(womenFilter, loan6Filter))
fun main(args: Array<String>) {
var arr = arrayListOf<Person>()
for (i in 1..10) {
var person = Person(i, "张" + i, 1 + Random().nextInt(2), (Random().nextInt(10)));
arr.add(person)
}
arr.forEach{
println(it)
}
println("=====planA=======")
filter(arr, planA).forEach {
println(it)
}
println("=====planB=======")
// println("=====Lambda======")
filter(arr, planB).forEach {
println(it)
}
println("==planA and planB==")
filter(arr,planA,planB).forEach {
println(it)
}
}
输入结果
Person(id=1, name=张1, sex=1, loan=5)
Person(id=2, name=张2, sex=1, loan=3)
Person(id=3, name=张3, sex=1, loan=6)
Person(id=4, name=张4, sex=2, loan=2)
Person(id=5, name=张5, sex=1, loan=7)
Person(id=6, name=张6, sex=2, loan=8)
Person(id=7, name=张7, sex=1, loan=4)
Person(id=8, name=张8, sex=1, loan=8)
Person(id=9, name=张9, sex=1, loan=1)
Person(id=10, name=张10, sex=2, loan=7)
=====planA=======
Person(id=1, name=张1, sex=1, loan=5)
Person(id=2, name=张2, sex=1, loan=3)
Person(id=3, name=张3, sex=1, loan=6)
Person(id=4, name=张4, sex=2, loan=2)
Person(id=5, name=张5, sex=1, loan=7)
Person(id=8, name=张8, sex=1, loan=8)
=====planB=======
Person(id=3, name=张3, sex=1, loan=6)
Person(id=5, name=张5, sex=1, loan=7)
Person(id=6, name=张6, sex=2, loan=8)
Person(id=8, name=张8, sex=1, loan=8)
Person(id=10, name=张10, sex=2, loan=7)
==planA and planB==
Person(id=3, name=张3, sex=1, loan=6)
Person(id=5, name=张5, sex=1, loan=7)
Person(id=8, name=张8, sex=1, loan=8)
访问者模式Visitor
功能:打印遍历当前文件夹下 mp3 或者 图片文件
import java.io.File
import java.io.FileFilter
import java.util.ArrayList
class MP3FileFilter : FileFilter {
override fun accept(file:java.io.File?): Boolean {
fun checkFileName():Boolean{ val name = file?.getName();
return name!!.endsWith(".mp3") || name!!.endsWith(".mp4")
}
return when(true)
{
file?.isDirectory->false
checkFileName()->true
else->false
}
}
}
class ImgFileFilter : FileFilter {
override fun accept(file:java.io.File?): Boolean {
fun checkFileName():Boolean{ val name = file?.getName();
return name!!.endsWith(".jpeg") || name!!.endsWith(".png")
}
return when(true)
{
file?.isDirectory->false
checkFileName()->true
else->false
}
}
}
fun getAllFile(baseFile: java.io.File,filter:FileFilter): List<java.io.File> = ArrayList<java.io.File>().apply {
if (baseFile.isFile() || !baseFile.exists()) {
return this
}
val files = baseFile.listFiles()
for (file in files) {
if (file.isDirectory()) {
getAllFile(file,filter)
} else {
if(filter.accept(file)) {
this.add(file)
}
}
}
}
fun main(args: Array<String>) {
println(getAllFile(java.io.File("."),MP3FileFilter()));
println(getAllFile(java.io.File("."),ImgFileFilter()));
}
输入结果
[]
[]