Skip to content

Commit

Permalink
审视类型定义
Browse files Browse the repository at this point in the history
添加 ReadMe

Signed-off-by: YangDR <[email protected]>
  • Loading branch information
YdrMaster committed Dec 5, 2018
1 parent 00d1cf7 commit 2f5ed66
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 98 deletions.
76 changes: 75 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,75 @@
# dependency
# 依赖管理器

本项目是对项目开发中常见的 *动态查找程序组件* 的抽象。通过定义一系列接口,规范了开发者对相互依赖的项目组件(全局资源和功能模块)进行弱耦合定义的操作。一些算法被用于支持开发者并发地将 **组件** `Component` **装载** `setup` 到到 **** `DynamicScope` 中,并在装载时确定组件依赖关系。

这个项目非常小,核心只包含 3 个重要的类,总代码量不到 200 行。

## 核心定义

* 组件 `Component`

所有的能从域中查找的东西,无论是否有状态或是否有依赖,都被归结为组件。这个接口除了标记作用,还声明了解决依赖冲突的方法。

```kotlin
interface Component {
override fun equals(other: Any?): Boolean
override fun hashCode(): Int
}
```

所有依赖项会被保存在域中的一个哈希集合中,而集合中不会包含两个相等的元素。这样,通过重载 `equals` ,组件就可以管理自身的冲突问题。

* 依赖者 `Dependent`

依赖者是希望找到域中其他组件的一类组件。

```kotlin
interface Dependent : Component {
fun sync(dependency: Component): Boolean
}
```

当一个新的组件被装载到动态域,所有尚未找齐依赖项的依赖者的 `sync` 方法会被调用,这时每个依赖者都可以检查新的组件是否自身的依赖项、保存依赖项的引用或利用其中的一些信息,并返回自身是否还关心以后到来的其他组件。

* 动态域

动态域是一个可继承的类,实现了上述的方法,当新组件到来时,更新组件表并通知依赖者更新依赖关系。

```kotlin
open class DynamicScope {
//组件集
// 用于查找特定组件类型和判定类型冲突
// 其中的组件只增加不减少
private val _components = ConcurrentHashSet<Component>()

//依赖者列表
// 用于在在新的依赖项到来时接收通知
// 其中的组件一旦集齐依赖项就会离开列表,不再接收通知
private val dependents = mutableListOf<(Component) -> Boolean>()

/** 浏览所有组件 */
val components = _components.view

/**
* 将一个新的组件加入到动态域,返回是否成功添加
* @return 若组件被添加到域,返回`true`
* 与已有的组件发生冲突时返回`false`
*/
open infix fun setup(component: Component) =
_components
.add(component)
.also {
// 更新依赖关系
if (it) synchronized(dependents) {
dependents.removeIf { it(component) }

if (component is Dependent)
component::sync
.takeIf { sync -> _components.none(sync) }
?.let(dependents::add)
}
}

...
}
```
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ plugins {
}

group = "org.mechdancer"
version = "0.1.0-dev-1"
version = "0.1.0-dev-2"

repositories {
mavenCentral()
Expand Down
55 changes: 0 additions & 55 deletions src/main/kotlin/org/mechdancer/dependency/AbstractDependent.kt

This file was deleted.

38 changes: 21 additions & 17 deletions src/main/kotlin/org/mechdancer/dependency/DynamicScope.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import java.util.concurrent.ConcurrentHashMap
* 动态域是域的一种,允许向其中动态地添加新的组件
* 组件被添加到动态域时,将执行一系列操作,以自动解算依赖关系和建立组件关联
*/
class DynamicScope {
open class DynamicScope {
//组件集
// 用于查找特定组件类型和判定类型冲突
// 其中的组件只增加不减少
Expand All @@ -18,22 +18,15 @@ class DynamicScope {
// 其中的组件一旦集齐依赖项就会离开列表,不再接收通知
private val dependents = mutableListOf<(Component) -> Boolean>()

//标记组件表
// 通过保存标记组件的引用来加速访问
private val _tagComponents = ConcurrentHashMap<String, TagComponent>()

/** 浏览所有组件 */
val components = _components.view

/** 浏览标记的组件 */
val tagComponents = buildView(_tagComponents)

/**
* 将一个新的组件加入到动态域,返回是否成功添加
* @return 若组件被添加到域,返回`true`
* 与已有的组件发生冲突时返回`false`
*/
infix fun setup(component: Component) =
open infix fun setup(component: Component) =
_components
.add(component)
.also {
Expand All @@ -43,23 +36,34 @@ class DynamicScope {

if (component is Dependent)
component::sync
.takeIf { sync -> components.none(sync) }
.takeIf { sync -> _components.none(sync) }
?.let(dependents::add)
}

// 保存标记组件
if (component is TagComponent)
if (null != _tagComponents.putIfAbsent(component.tag, component))
throw RuntimeException("try to add the second component with tag ${component.tag}")
}

/** 线程安全的哈希集,仿照跳表集,基于映射构造 */
private class ConcurrentHashSet<T : Any> {
private class ConcurrentHashSet<T : Any> : MutableSet<T> {

private object PlaceHolder

private val core = ConcurrentHashMap<T, PlaceHolder>()
val view = object : Set<T> by core.keys {}
override val size get() = core.size

override fun iterator(): MutableIterator<T> = core.keys.iterator()

override fun add(element: T) = core.putIfAbsent(element, PlaceHolder) == null
override fun addAll(elements: Collection<T>) = elements.all(::add)

override fun remove(element: T) = core.remove(element) != null
override fun removeAll(elements: Collection<T>) = elements.all(::remove)
override fun clear() = core.clear()

override fun retainAll(elements: Collection<T>) = removeAll(core.keys.filter { it !in elements })

override operator fun contains(element: T) = core.containsKey(element)
override fun containsAll(elements: Collection<T>) = elements.all(::contains)

fun add(it: T) = core.putIfAbsent(it, PlaceHolder) == null
override fun isEmpty() = core.isEmpty()
}
}
10 changes: 3 additions & 7 deletions src/main/kotlin/org/mechdancer/dependency/Functions.kt
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
package org.mechdancer.dependency

/** 计算类型的哈希值 */
inline fun <reified C : Component> hashOf() =
C::class.java.hashCode()

/** 找到一种 [C] 类型的依赖 */
inline fun <reified C : Component> Set<Component>.get(): List<C> =
inline fun <reified C : Component> Iterable<Component>.get(): List<C> =
mapNotNull { it as? C }

/** 找到一种 [C] 类型的依赖 */
inline fun <reified C : Component> Set<Component>.maybe(): C? =
inline fun <reified C : Component> Iterable<Component>.maybe(): C? =
get<C>().singleOrNull()

/** 找到一种 [C] 类型的依赖 */
inline fun <reified C : Component> Set<Component>.must(): C =
inline fun <reified C : Component> Iterable<Component>.must(): C =
maybe() ?: throw ComponentNotExistException(C::class)

/** 向动态域添加新的依赖项 */
Expand Down
9 changes: 0 additions & 9 deletions src/main/kotlin/org/mechdancer/dependency/TagComponent.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.mechdancer.dependency
package org.mechdancer.dependency.unique

import org.mechdancer.dependency.Component
import kotlin.reflect.KClass
import kotlin.reflect.full.safeCast

Expand All @@ -9,7 +10,7 @@ import kotlin.reflect.full.safeCast
* 需要实现类提供自己的具体类型 [type]
* 泛型 [T] 可保证此类型来自这个实现类
*/
abstract class AbstractComponent<T : AbstractComponent<T>>
abstract class UniqueComponent<T : UniqueComponent<T>>
(private val type: KClass<T>) : Component {

override fun equals(other: Any?) =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package org.mechdancer.dependency
package org.mechdancer.dependency.unique

import org.mechdancer.dependency.Component
import org.mechdancer.dependency.ComponentNotExistException
import java.util.concurrent.atomic.AtomicReference
import kotlin.reflect.KClass
import kotlin.reflect.full.safeCast

/**
* 类型 [T] 的依赖项
* 具体到类型 [T] 并依类型判别冲突的依赖项
* 保存到组件实例的引用
* 线程安全
*/
sealed class AbstractDependency<T : Component>(val type: KClass<T>) {
sealed class UniqueDependency<T : Component>(val type: KClass<T>) {
private val _field = AtomicReference<T?>(null)

/** 尝试置入值 [value],若无法转换到目标类型则不产生作用 */
Expand All @@ -19,13 +21,13 @@ sealed class AbstractDependency<T : Component>(val type: KClass<T>) {
open val field: T? get() = _field.get()

/** 类型 [T] 的弱依赖项 */
class WeakDependency<T : Component>(type: KClass<T>) : AbstractDependency<T>(type)
class WeakDependency<T : Component>(type: KClass<T>) : UniqueDependency<T>(type)

/** 类型 [T] 的强依赖项 */
class Dependency<T : Component>(type: KClass<T>) : AbstractDependency<T>(type) {
class Dependency<T : Component>(type: KClass<T>) : UniqueDependency<T>(type) {
override val field: T get() = super.field ?: throw ComponentNotExistException(type)
}

override fun equals(other: Any?) = this === other || (other as? AbstractDependency<*>)?.type == type
override fun equals(other: Any?) = this === other || (other as? UniqueDependency<*>)?.type == type
override fun hashCode() = type.hashCode()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.mechdancer.dependency.unique

import org.mechdancer.dependency.Component
import org.mechdancer.dependency.Dependent
import org.mechdancer.dependency.unique.UniqueDependency.Dependency
import org.mechdancer.dependency.unique.UniqueDependency.WeakDependency
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KClass
import kotlin.reflect.KProperty

/**
* 以类型区分的依赖项管理
* 应聚合到 `Dependent` 内部
*/
class UniqueDependencyManager {
// 尚未装载的依赖项集
private val dependencies = hashSetOf<UniqueDependency<*>>()

// 添加依赖项到集合,发生冲突时产生异常
private fun <T : Component> add(dependency: UniqueDependency<T>, type: KClass<T>) =
synchronized(dependencies) {
if (!dependencies.add(dependency))
throw RuntimeException("try to add the second ${type.qualifiedName}")
}

/** 每一次扫描都清除成功装载的依赖项 */
fun sync(dependency: Component) =
synchronized(dependencies) {
dependencies.removeIf { it.set(dependency) != null } && dependencies.isEmpty()
}

/** 构造一个 [C] 类型的强依赖 */
infix fun <C : Component> dependOnStrict(type: KClass<C>) =
Dependency(type).also { add(it, type) }

/** 构造一个 [C] 类型的弱依赖 */
infix fun <C : Component> dependOnWeak(type: KClass<C>) =
WeakDependency(type).also { add(it, type) }

/** 构造一个 [C] 类型的强依赖 */
inline fun <reified C : Component> dependency() = dependOnStrict(C::class)

/** 构造一个 [C] 类型的弱依赖 */
inline fun <reified C : Component> weakDependency() = dependOnWeak(C::class)

/** 从一个 [C] 类型的强依赖取值 */
inline fun <reified C : Component, T> must(crossinline block: (C) -> T): Lazy<T> {
val dependency = dependency<C>()
return lazy { dependency.field.let(block) }
}

/** 从一个 [C] 类型的弱依赖取值 */
inline fun <reified C : Component, T> maybe(default: T, crossinline block: (C) -> T): Lazy<T> {
val dependency = weakDependency<C>()
return lazy { dependency.field?.let(block) ?: default }
}

/** 构造一个 [C] 类型的强依赖属性代理 */
inline fun <reified C : Component> must() =
object : ReadOnlyProperty<Dependent, C> {
private val core = dependency<C>()
override fun getValue(thisRef: Dependent, property: KProperty<*>) = core.field
}

/** 构造一个 [C] 类型的弱依赖属性代理 */
inline fun <reified C : Component> maybe() =
object : ReadOnlyProperty<Dependent, C?> {
private val core = weakDependency<C>()
override fun getValue(thisRef: Dependent, property: KProperty<*>) = core.field
}
}

0 comments on commit 2f5ed66

Please sign in to comment.