Clyde学习笔记一(Scope)

Scope相关的接口、类都定义在expr这个包中,官方的说明很简单,只有一句话:expr - expression evaluation and symbol binding,但scope这个概念却很重要,可以说是整个clyde框架的核心基石之一。那么它到底是个什么概念,又起到了什么作用呢?首先它是一个接口,在这个接口中,最重要的就是下面这个方法:

 

public <T> T get (String name, Class<T> clazz);
 

 

再看它的注释:

 

Looks up a symbol in this scope,return the mapping for the requested symbol。

 

在这里,symbol指的就是参数name,这个方法的作用就是找到name这个symbol所对应的值,并且这个值的类型是T。

 

接下来我们再来看下这个方法的实现。scope有两个默认的实现类,分别是SimpleScope和DynamicScope。

 

在SimpleScope中的实现:

 

 

    public <T> T get (String name, Class<T> clazz)
    {
        return ScopeUtil.get(this, name, clazz);
    }

 那么具体的逻辑是写在了ScopeUtil中,在ScopeUtil.get方法中,有关键的这句:

 

 

Member member = getScoped(object.getClass()).get(name);
 

这句话的意思是在object这个类中所有用scoped annotation标注过的属性或方法中找到与name对应的那个。

相关代码如下:

 

 

        HashMap<String, Member> members = new HashMap<String, Member>();
        Class<?> sclazz = clazz.getSuperclass();
        if (sclazz != null) {
            members.putAll(getScoped(sclazz));
        }
        // add all scoped fields (stripping off the leading underscore, if present)
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(Scoped.class)) {
                field.setAccessible(true);
                members.put(stripUnderscore(field.getName()), field);
            }
        }
        // add all scoped methods
        for (Method method : clazz.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Scoped.class)) {
                method.setAccessible(true);
                members.put(method.getName(), method);
            }
        }

 可以看到每个类都有一个对应的map,这个map中保存了所用用scoped标注过的属性和方法,并且以属性和方法名作为map的key,这个key就是我们前面所说的symbol,即那个name参数。在这里的整个方法还递归的包括了这个类所有的超类,但是要主要到这里的scoped是个annotation,和我们前面提到的scope接口不是同一回事。每个类对应的map还保存在一个全局的map中作为cache,这样就不用每次都反射查找一遍。

 

 

    /** Cached scoped members. */
    protected static HashMap<Class<?>, HashMap<String, Member>> _scoped = Maps.newHashMap();
 

找到对应的属性或方法之后,ScopeUtil的get方法就返回属性的值或者执行方法的结果,在这里相关代码就不展开了。现在回过头来重新审视一下scopeUtil的get方法,那就是:

 

找到在object这个类中所有用scoped annotation标注过的属性或方法中查找属性或方法名为name的那个,并返回属性的值或方法执行的结果,返回类型为T。在simpleScope中,这个object就是它自身。

 

再来看一下dynamicScope的实现:

 

 

    public <T> T get (String name, Class<T> clazz)
    {
        // first try the dynamic symbols, then the reflective ones
        Object value = (_symbols == null) ? null : _symbols.get(name);
        return clazz.isInstance(value) ? clazz.cast(value) : ScopeUtil.get(_owner, name, clazz);
    }
 

可以看到,在dynamicScope中,这个object不再是它自己,而是_owner。看一下owner的定义:

 

 

    /** The owner of this scope. */
    protected Object _owner;

 这也是SimpleScope和DynamicScope最重要的一个区别。

 

现在我们已经初步了解了scope的概念,那么这个scope有什么具体的作用呢?

在scope接口中还有两个方法,addListener,removeListener。

 

 

    /**
     * Adds a listener for changes in scope.  The listener will be notified when symbols are
     * added or removed and whenever the scope hierarchy changes.
     */
    public void addListener (ScopeUpdateListener listener);

    /**
     * Removes a listener for changes in scope.
     */
    public void removeListener (ScopeUpdateListener listener);
 

 

再来看一下ScopeUpdateListener这个接口,这个接口SimpleScope和DynamicScope都默认实现了,也就是说SimpleScope和DynamicScope都可以作为监听器监听其他的scope,一旦它监听的scope被改变,scopeUpdated方法都会被调用。

 

 

/**
 * Used to notify objects when the scope has been updated.
 */
public interface ScopeUpdateListener
{
    /**
     * Called when the scope has been updated.
     */
    public void scopeUpdated (ScopeEvent event);
}

 

下面是SimpleScope的scopeUpdate方法的实现。

 

 

    public void scopeUpdated (ScopeEvent event)
    {
        ScopeUtil.updateBound(this, _parentScope);
    }

再看一下ScopeUtil的updateBound方法:

 

 

    /**
     * Updates the {@link Bound} fields of the specified object using the provided scope.
     */
    public static void updateBound (Object object, Scope scope)
    {
        for (Field field : getBound(object.getClass())) {
            String name = field.getAnnotation(Bound.class).value();
            if (name.length() == 0) {
                name = stripUnderscore(field.getName());
            }
            @SuppressWarnings("unchecked") Class<Object> type = (Class<Object>)field.getType();
            try {
                field.set(object, resolve(scope, name, field.get(object), type));
            } catch (IllegalAccessException e) {
                log.warning("Error accessing bound field.", "field", field, e);
            }
        }
    }

 这里也是用的反射找到object类中用Bound annotation标注的属性,并且找到这个属性所bound(绑定)的symbol,resolve出这个symbol的值并赋值给这个属性。

 

再看一下ScopeUtil中resolve方法的实现。

 

 

    /**
     * Attempts to resolve the identified symbol in the given scope.  If not found there,
     * searches the parent of that scope, and so on.
     *
     * @return the mapping for the symbol, or <code>defvalue</code> if not found anywhere in the
     * chain.
     */
    public static <T> T resolve (Scope scope, String name, T defvalue, Class<T> clazz)
    {
        // if the name includes a scope qualifier, look for that scope
        int idx = name.indexOf(':');
        if (idx != -1) {
            String qualifier = name.substring(0, idx);
            name = name.substring(idx + 1);
            while (scope != null && !qualifier.equals(scope.getScopeName())) {
                scope = scope.getParentScope();
            }
        }

        // rise up through the scopes looking for the requested symbol
        for (; scope != null; scope = scope.getParentScope()) {
            T value = scope.get(name, clazz);
            if (value != null) {
                return value;
            }
        }

        // no luck; return the default value
        return defvalue;
    }
 

这个方法就是在给定的scope中找到symbol所对应的值,在当前scope中找不到可以递归的在当前scope的parentScope中继续寻找,并且symbol还可以用“:”分隔符指定一个特定的scope。在上面的代码中我们看到了熟悉一句:

 

 

 T value = scope.get(name, clazz);
 

怎么样,到这里整个拼图中的两块已经连在了一起,并且已经隐约看到了整个scope框架它所需要表达的一个意思,那就是:

 

当一个scope有update时,所有监听该scope的其他scope所拥有的object中,任何绑定到该scope中symbol的属性值都会随着该symbol的值变化而变化。这也正是官方介绍中的symbol binding的概念所在。应该说这个表述非常的抽象,但它却是整个clyde框架的基石,框架中的其他部分有非常多的依赖于这个抽象的概念。回过头来我们再一次看到,在SimpleScope中,object还是它自身,而DynamicScope的object仍然还是它的owner。

 

 

    public void scopeUpdated (ScopeEvent event)
    {
        ScopeUtil.updateBound(_owner, _parentScope);
        wasUpdated();
    }
 

每个scope默认的监听对象都是该scope的parentScope。SimpleScope中的构造函数:

 

 

    /**
     * Creates a new simple scope.
     */
    public SimpleScope (Scope parentScope)
    {
        if ((_parentScope = parentScope) != null) {
            _parentScope.addListener(this);
        }
        ......
    }

 

DynamicScope也是如此。

 

下面写一段测试代码来验证一下。

 

 

package com.meidusa.clyde.test;

import com.threerings.expr.Bound;
import com.threerings.expr.DynamicScope;
import com.threerings.expr.Scope;
import com.threerings.expr.Scoped;
import com.threerings.expr.SimpleScope;

public class TestScope {
	
	public static class TestScoped extends DynamicScope{

		public TestScoped(Scope parentScope) {
			super("test name", parentScope);
		}
		
		@Scoped
		protected String scopedString = "before test";

		public String getScopedString() {
			return scopedString;
		}

		public void setScopedString(String scopedString) {
			this.scopedString = scopedString;
		}
		
	}
	
	public static class TestBounded extends SimpleScope{

		public TestBounded(Scope parentScope) {
			super(parentScope);
		}
		
		@Bound("scopedString")
		protected String boundedString;

		public String getBoundedString() {
			return boundedString;
		}

		public void setBoundedString(String boundedString) {
			this.boundedString = boundedString;
		}
		
	}

	public static void main(String[] args){
		TestScoped parent = new TestScoped(null);
		TestBounded child = new TestBounded(parent);
		System.out.println(child.getBoundedString());
		parent.setScopedString("after test");
		parent.wasUpdated();
		System.out.println(child.getBoundedString());
	}
}

 

运行后输出为:

 

 

before test
after test
 

 

 

内容概要:本文详细介绍了智慧社区系统的多个关键技术模块及其代码实现,涵盖智能照明、楼控系统、安防系统以及运维管理等方面。首先探讨了智能照明系统的实现逻辑,通过人体移动传感器和环境光强度进行双重要素判断,确保照明系统的智能化运作。接着深入分析了楼控系统中的电梯调度算法,强调了动态负载均衡算法的应用,特别是在高峰时段的优化调度。对于安防系统,则着重于门禁系统和视频监控的联动,利用事件驱动机制实现异常情况的及时响应。最后讨论了可视化大屏的数据展示技术,采用ECharts等工具实现高效的数据可视化。此外,还提到了设备台账管理和运维管理中的定时任务脚本,展示了如何通过代码解决实际问题。 适用人群:适用于具有定编程基础的研发人员和技术爱好者,特别是对物联网、智能家居等领域感兴趣的开发者。 使用场景及目标:帮助读者理解并掌握智慧社区各子系统的具体实现方法,能够应用于实际项目的开发中,提升系统的智能化水平和用户体验。 其他说明:文中不仅提供了具体的代码示例,还分享了许多实战经验和技巧,如MQTT协议用于设备通信、WebSocket用于状态同步、ECharts用于数据可视化等。同时指出了实际开发过程中可能会遇到的问题及解决方案,如设备状态同步、视频流处理性能优化等。 适合人群:具备定编程基础,对物联网、智能家居等领域感兴趣的研发人员和技术爱好者。 使用场景及目标:①理解智慧社区各子系统的具体实现方法;②将相关技术应用到实际项目开发中,提高系统的智能化水平和用户体验。 阅读建议:本文不仅提供具体代码示例,还分享了大量实战经验与技巧,在学习过程中应重点关注这些实践经验,并结合自身项目情况进行实践探索。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值