精华内容
下载资源
问答
  • EA&UML日拱一卒-关联(关联类

    千次阅读 2017-04-12 20:18:36
    举例说明什么是关联类,怎么用关联类

    正如可以使用属性描述类的对象一样,也可以用属性来描述关联。UML用关联类来表示这样的信息。关联类(association class)是一种关联,也是一个类。

    -----------UML面向对象建模与设计


    也不知道你是懂了呢还是懂了呢?还先从一个简单的例子开始说起吧。


    有一个温度控制系统,通过传感器测量温度。传感器的输出是1v到5v,对应的温度为0到100摄氏度。


    控制器每0.1秒获取一次温度值,然后根据实际温度和期望的温度的偏差来决定输出值,计算的周期为1秒,输出值的范围为0%到100%。这个输出值发送给一台加热器来控制温度。


    加热器的控制端在输入1v时的输出功率为0KW,输入5v是输出功率为10KW。


    这个系统应该如何建模呢?先来第一步,识别类和关联。




    接下来将全部信息都反映到模型上。




    不要被满篇的属性吓倒,耐心地,慢慢地读下去,你会理解的。


    传感器Sensor

    传感器Sensor的功能其实就是将现实世界中的0度(m_tempLow)到100度(m_tempHigh)的温度经过线性变换转换成1v(m_outputLow)到5v(m_outputHigh)的电压信号。


    控制器Controller

    控 制器每0.1秒(m_sampleCycle)获取一次Sensor的电压输出,将这个电压值从范围 [m_sensorOutoutLow,m_sensorOutputHigh]线性变换到[m_tempLow,m_tempHight]之间,然后由 控制器根据实际温度的和期望温度偏差来决定输出值,计算的周期为1秒(m_controlCycle),输出值的范围为0% (m_controllerOutoutLow)到100%(m_controllerOutoutHigh)。这个输出值再经过线性变换变成一个 [m_heaterInputLow,m_heaterInputHigh]之间的值,发送给加热器来控制温度。


    加热器Heater

    加热器的控制端接受到1v(m_intputLow)到5v(m_intputHigh)之间的电压值以后经过线性变换转换成0KW(m_outoutLow)到10KW(m_outputHigh)之间的功率。


    谢谢你坚持读到这里。回头来审视一下模型,有没有发现什么问题?


    是的,Controller类太大,功能也太多了。


    这个问题的解决方案就是本文的话题:关联类。当关联足够复杂,复杂到必须需要利用属性来描述细节,利用操作来定义动作的时候就该关联类出场了。


    在本例中取得温度值(GetTemperature),输出(SetOutput)两个关联,要进行线性变换,各自需要四个属性(实际上还应该有操作),都可以定义为关联类。就像下面这样。




    前面废了那么多口舌,到主角的时候反而简单了。


    如果要总结的话,关联类的内容就是补充描述关联的那些信息


    重要的事情说了三遍,你理解了吧。那就回去练习,你也找个场景试试。这种事情不落地,弄不好一辈子学不会。




    如果阅读本文能给您带来些许收获,欢迎分享给更多的朋友!

    阅读更多新文章,请扫描下面二维码,关注公众号【面向对象思考】


    展开全文
  • JavaBean的属性与一般Java程序中所指的属性,或者说与所有面向对象的程序设计语言中对象的属性是... 本文主要介绍如何使用PropertyChangeSupport来支持关联属性事件的触发。  1.关联属性  关联属性,也称之为绑

        JavaBean的属性与一般Java程序中所指的属性,或者说与所有面向对象的程序设计语言中对象的属性是一个概念,在程序中的具体体现就是类中的变量。在JavaBean的设计中,按照属性的不同作用又细分为四类:单值属性索引属性关联属性限制属性

      本文主要介绍如何使用PropertyChangeSupport类来支持关联属性事件的触发。

      1.关联属性

      关联属性,也称之为绑定属性。绑定属性会在属性值发生变化时,通知所有相关的监听器。为了实现一个绑定属性,必须实现两个机制。

      1) 无论何时,只要属性的值发生变化,该bean必须发送一个PropertyChange事件给所有已注册的监听器。该变化可能发生在调用set方法时,或者程序的用户做出某种动作时。

      2) 为了使感兴趣的监听器能够进行注册,bean必须实现以下两个方法:

    void addPropertyChangeListener(PropertyChangeListener listener);

    void removePropertyChangeListener(PropertyChangeListener listener);

      2.使用PropertyChangeSupport 管理 监听器

      可以通过java.bean包下的PropertyChangeSupport类来管理监听器。要使用这个类,bean必须有一个此类的数据域。

    private PropertyChangeSupport changes = new PropertyChangeSupport(this);

      这样就可以将添加和移除监听器的任务交给这个对象。

    public void addPropertyChangeListener(PropertyChangeListener listener) {

      changes.addPropertyChangeListener(listener);

    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {

      changes.removePropertyChangeListener(listener);

    }

        当bean的属性发生变化时,使用PropertyChangeSupport对象的firePropertyChange方法,它会将一个事件发送给所有已经注册的监听器。该方法有三个参数:属性的名字、旧的值以及新的值。属性的值必须是对象,如果是简单数据类型,则必须进行包装。

     changes.firePropertyChange("ourString", oldString, newString);

      所有注册的监听器实现PropertyChangeListener接口,该接口中只有一个方法。

    public void propertyChange(PropertyChangeEvent e);

      当bean的属性值发生变化时,该方法中的代码就会被触发。可以通过

      e.getOldValue();

      e.getNewValue();

      来得到changes.firePropertyChange("ourString", oldString, newString);中的oldString和newString。

      3.为什么要使用PropertyChangeSupport

      使用这个类 管理 监听器的好处:

        1)它是线程安全的。如果使用一个循环体来set Bean的属性,则这个类可以保证所有监听器执行触发事件的有序。

      2)这个类支持fire带索引的属性改变事件(详见java.bean.IndexedPropertyChangeEvent)。此时向注册的监听器发送一个

           PropertyChangeEvent的方法为:

    void fireIndexedPropertyChange(String PropertyName,int index,Object oldValue,Object newValue);

      4.示例

      MyBoundBean类(具体代码见附件)是一个JavaBean,我们关注它的唯一一个属性ourString的变化情况,它的初始值是Hello。并通过PropertyChange类来管理监听器。注意在set方法中会调用firePropertyChange方法。

    MyBoundBean.java
    import java.beans.PropertyChangeListener;
    import java.beans.PropertyChangeSupport;
    public class MyBoundBean {
      String ourString = "Hello";
      private PropertyChangeSupport changes = new PropertyChangeSupport(this);
      public void setString(String newString) {
        String oldString = ourString;
        ourString = newString;
        changes.firePropertyChange("ourString", oldString, newString);
      }
      public String getString() {
        return ourString;
      }
      public void addPropertyChangeListener(PropertyChangeListener listener) {
        changes.addPropertyChangeListener(listener);
      }
      public void removePropertyChangeListener(PropertyChangeListener listener) {
        changes.removePropertyChangeListener(listener);
      }
    }

    Java:在Bean中使用PropertyChangeSupport支持PropertyChangeListeners

     

    MyBoundBean b = new MyBoundBean();

    public void actionPerformed(ActionEvent e) {
      jButton1.setText(textBox.getText());
      b.setString(textBox.getText());
    }

      目标bean的属性一改变(注意,初始值是"Hello"),将会触发propertyChange方法的执行。将文本框的内容设置为目标bean的ourString属性的旧值,同时,将jButton2的test设置成目标bean的ourString属性的新值。

    public void propertyChange(PropertyChangeEvent e) {
      if (e.getSource() == b) {
        textBox.setText(e.getOldValue().toString());
        jButton2.setText(e.getNewValue().toString());
      }
    }

    Java:在Bean中使用PropertyChangeSupport支持PropertyChangeListeners

      如果不实现PropertyChangeListener接口的话,可以使用匿名内部类来达到同样的效果。(具体代码见附件MyCallBound2.java)

    MyBoundBean b = new MyBoundBean();

    b.addPropertyChangeListener(new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent e) {
        // 这样一来,我们就可以用自己定义的名字实现事件
        ourString_propertyChange(e);
      }
    });

     

      这样一来,我们就可以用自己定义的名字实现事件。

    void ourString_propertyChange(PropertyChangeEvent e) {
      if (e.getSource() == b) {
        textBox.setText(e.getOldValue().toString());
        jButton2.setText(e.getNewValue().toString());
      }
    }

    展开全文
  • 使用分类可以为没有源码的增加方法,但是一般不能增加属性。如果我们为分类添加属性的话,要手动实现所加属性的getter和setter方法,这里使用关联对象的方式完成set和get方法。 我们首先了解@property的意思 ...

    使用分类可以为没有源码的类增加方法,但是一般不能增加属性。如果我们为分类添加属性的话,要手动实现所加属性的getter和setter方法,这里使用关联对象的方式完成set和get方法。

    我们首先了解@property的意思

    • 生成实例变量 _property
    • 生成 getter 方法
    • property 生成 setter方法 - setProperty:

    如下,为一个分类增加一个名为name的字符串属性。

    #import <objc/runtime.h> //需要用到runtime
    
    @property (nonatomic,copy) NSString *name; 
    
    static const char nameKey;
    

    set和get方法如下:
    在这里插入图片描述
    自己实现name的set和get方法,用到objc_setAssociatedObjectobjc_getAssociatedObject方法将属性name和对象关联起来(用到runtime)。

    objc_setAssociatedObject需要四个参数分别是,所关联的对象,静态指针static void *类型的参数,需要关联的值,属性的修饰符。

    objc_getAssociatedObject需要两个参数,所关联的对象,静态指针类型的参数

    在这里插入图片描述
    完成后如图所示,namekey是一个static const char的字符。因为添加的属性是字符串,所以我们使用OBJC_ASSOCIATION_COPY来修饰该属性,对应的copy,对照表如下
    在这里插入图片描述
    完成关联后,该类就新增了一个name的字符串属性。

    参考链接

    展开全文
  • 给分类添加“属性”咱们知道,分类中可以添加方法,却无法添加属性。那咱们有其他的方法来实现吗? 先来看看下面这段代码:@interface UIView (nl_Frame) @property (nonatomic, assign) CGFloat nl_width; @end @...

    给分类添加属性

      咱们知道,分类中可以添加方法,却无法添加实例变量。那咱们有什么方法在既有类中存放自定义数据呢?
    先来看看下面这段代码:

    @interface UIView (nl_Frame)
    @property (nonatomic, assign) CGFloat nl_width;
    @end
     @implementation UIView (nl_Frame)
    - (void)setNl_width:(CGFloat)nl_width {
      CGRect frame = self.frame;
      frame.size.width = nl_width;
      self.frame = frame;
    }
    
    - (CGFloat)nl_width {
      return CGRectGetWidth(self.frame);
    }
    @end

      在这里给 UIView增加了一个宽度属性:nl_width,而且为其实现了相应的 getter和 setter方法(nl_widthsetNl_width:)。这两个方法实际上访问的 frame属性,如果你有注意过的话,你会发现frame也是定义在分类里边的:

    @interface UIView(UIViewGeometry)
    @property(nonatomic) CGRect            frame;
    //...
    @end

      可以看到,这种定义在分类里的属性,实际上是实现了相应的方法,并在方法里边通过访问其它属性来达到目的。这通常用来简化某些操作,比如定义咱们这个分类后,获取视图的宽度只要view.nl_width就可以了,再不用CGRectGetWidth(view.frame)来得到宽度,而且可读性也增强了很多。

      再来看看这个需求:在 sqlite中,第一个表如果在没有指定主键的情况下,那默认就会定义一个主键rowid。咱们就把这个 rowid直接放到 NSObject里边,作为属性,那么任何对象也会有这个主键rowid了。但是这个rowid却无法像上边的nl_width一样通过访问其它属性来达到目的。那该怎么办?

    关联对象

      本节的主角出场了:关联对象
      在使用关联对象之前,得先引入头文件:

    #import <objc/runtime.h>

      可以在该头文件中找到三个允许你将任何键值在运行时关联到对象上的函数:

    objc_setAssociatedObject       // 设置关联对象
    objc_getAssociatedObject       // 获取关联对象
    objc_removeAssociatedObjects   // 移除关联对象

    既然有了这个工具,那么咱们再来看看:

    @interface NSObject (nl_sqlite)
    @property (nonatomic, assign) NSUInteger rowid;
    @end
    @implementation NSObject (nl_sqlite)
    static void *nl_sqlite_rowid_key = &nl_sqlite_rowid_key;
    - (void)setRowid:(NSUInteger)rowid {
      objc_setAssociatedObject(self, nl_sqlite_rowid_key, @(rowid), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    - (NSUInteger)rowid {
      return [objc_getAssociatedObject(self, nl_sqlite_rowid_key) unsignedLongValue];
    }
    @end

      上面的代码,就是通过关联对象给NSObject增加了一个rowid“属性”。关联对象在使用时,需要咱们提供一个指针,即key,用来识别被关联的对象。咱们这里的key就是一个空指针:nl_sqlite_rowid_key。当然,你也可以@selector(rowid)来作为 key(常用)。
    于是,就可以这么来用了:

    id person = [NSObject new];
    person.rowid = 1;

      很爽吧!以后就可以给已有类添加“属性”了。这可是一个很强大的功能哟,如果你查看过一些强大的第三方库的话,就会发现,这是一个常用的技巧。

    关联类型等效的@property属性
    OBJC_ASSOCIATION_ASSIGNassign
    OBJC_ASSOCIATION_RETAIN_NONATOMICnonatomic, retain
    OBJC_ASSOCIATION_COPY_NONATOMICnonatomic, copy
    OBJC_ASSOCIATION_RETAINretain
    OBJC_ASSOCIATION_COPYcopy

    为什么分类无法添加实例变量

      这个问题牵扯到内存布局。有一个个人信息的类,定义的实例变量如下:

    @interface Person : NSObject {
      NSString *_firstName;
      NSString *_lastName;
      NSString *_someInternalData;
    }

      如果你对 C++或 Java比较熟悉的话,那你也应该比较熟悉这种写法,在这些语言中,可以定义实例变量的作用域。然而编写 OC代码时,却很少这么做。这种写法的问题是:对象布局在编译期就已经固定了。只要碰到访问_firstName变量的代码,编译器就把其替换为“偏移量”(offset),这个偏移量是“硬编码”(hardcode),表示该变量距离存放对象的内存区域的起始地址有多远。这样做目前来看没问题,但是如果又加了一个实例变量,那就麻烦了。比如说,假设在_firstName之前又多了一个实例变量:

    @interface Person : NSObject {
      NSDate *_dateOfBirth;
      NSString *_firstName;
      NSString *_lastName;
      NSString *_someInternalData;
    }

      原来表示_firstName的偏移量现在却指向_dateOfBirth了。把偏移量硬编码于其中的那么代码都会读取到错误的值。
      如果代码使用了编译期计算出来的偏移量,那么在修改类定义之后必须重新编译,否则就会出错。例如,某个代码库中的代码使用了一份旧的类定义。如果和其相链接的代码使用了新的定义,那么运行时就会出现不兼容现象。当然,真实的情况远比这复杂。
      所以在分类中,自然也就无法添加实例变量了。不然会打乱类中的偏移量。
      

    关联对象的基本原理

      OC已开源:http://opensource.apple.com/tarballs/objc4/objc4-646.tar.gz
      这里只分析其基本原理:
      在运行时环境中,有一个全局的 hashMap:associations。它用来记录那些有“关联对象”的对象。当一个对象object第一次关联对象时,这个 associations就将其作为 key加入到 hashMap中,而 value则是一另一个 map对象。就以上面的 rowid来说,当第一次 setRowid时,伪代码如下:

      ObjectAssociationMap *refs = new ObjectAssociationMap;
      associations[object] = refs;
      (*refs)[key] = ObjcAssociation(policy, rowid);

      看到这里,对象跟 NSDictionary很像呢!把关联到该对象的值看成字典中的 value。于是,存取关联对象的值就相当于在 NSDictionary对象上调用[object setObject:value forKey:key]与[object objectForKey:key]方法。然而两者之间有个重要的差别:设置关联对象时用的 key是个“不透明的指针”。如果在两个 key上调用“isEqual:”方法的返回值是 YES,那么 NSDictionary就认为二者相等;然而在设置关联对象值时,若想令两个键匹配到同一个值,则二者必须是完全相同的指针才行。

    展开全文
  • 通过给系统建立类别(Category)文件,使用运行时关联值的方法为系统添加属性
  • 这样使用之后,xml中的所有属性都需要被待转化的模型识别,假如有一个字段没有对应上,即会抛出错误。 问题解决方案 XStream 官方也提供这样一种构造方法。 XStream xstream = new XStream() { @...
  • SLTMonitStation 中 @ManyToOne(cascade=CascadeType.ALL) @JoinColumn(name="ADDVCD",referencedColumnName="ITEM_CODE",unique=true,nullable=false,insertable = false,updatable = false) pri
  • JavaBean 设置关联属性

    千次阅读 2004-09-28 15:40:00
    在一个Bean中设置关联属性的基本步骤如下:调入java.beans 包,以便访问该包中所定义的一些方便。MyButton中的import语句的使用方法如下:import java.beans.*; 实例化java.beans.PropertyChangeSupport。...
  • 问题一:如果我们想要用离线DetachedCriteria中设置对象的关联属性的查询条件,那么要为关联属性设置一个别名!! detachedCriteria.createAlias("关联属性名", "别名"),请看示例:“比如我在...
  • 最近在做项目的时候,遇见一个问题,项目架构是hibernate spring sprimgmvc,我有么一个A,A里面有个属性B,A和B是多对一关系.我在前台form表单里面保存A的时候也需要把B的id保存起来,我就这么定义了一个input: ...
  • 一、一对一关联  1.1、提出需求  根据班级id查询班级信息(带老师的信息) 1.2、创建表和数据  创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关系。...
  • 上回 说了 Hibernate中的单向一对多关联 和 Hibernate中的单向多对一关联。这次针对这两个“单向... 在Grade中需要添加 Set集合保存Student对象,并且在Grade.hbm.xml的映射配置文件中,针对Set集合添加如下配置:
  • 相关文章: 《Runtime的初步认识——结构体与》 ...利用 Category 给现有的添加属性比如我们要给一个 NSArray 添加一个属性叫做NSString *name。我们首先新建一个Objective-C文件。File: NameFile Type:Cat
  • Python——类属性/实例属性

    万次阅读 2014-03-19 22:25:12
    一、类属性  类属性仅与其被定义的类相绑定。类数据属性仅当需要有更加“静态”数据类型时才变得有用,它和任何实例都无关。  1. 类的数据属性  数据属性仅仅是所定义的类的变量。这种属性已被 OO 程序员所熟悉,...
  • author:咔咔 wechat:fangkangfk 这个案例是获取轮播图...出现这个问题就是在使用关联预加载的时候必须带上关联外键的主键,否则就会报出这个错 所以修改后的代码,必须加上关联模型的主键 测试数据: ...
  • 因此通常情况下都只需写出Publc/Internal方法、属性即可。(就算是私有的方法非常重要,如果没有体现和其余之间关系,可以不写) 一、聚合Aggregation(拥有关系):体现了整体与部分 如:学校与学生之间 二...
  • Hibernate:组件属性关联映射的区别
  • MyBatis处理表字段与实体类属性不一致
  • 矢量数据属性表和表格关联

    千次阅读 2018-10-13 00:19:06
    矢量数据属性表和表格关联:  1、一对一关系:连接 2、一对多关系:创建查询表 例如:矢量数据属性表的ID字段的值和表格的HXID字段的值形成一对多关系,则可以使用“创建查询表”工具可对数据应用 SQL 查询,...
  • 的几种关联模式的讲解

    万次阅读 2019-02-19 23:17:03
    1.单向关联一般是把B作为A的一个属性来实用,例如Company是一个,Employee是一个。然而Company将Employee作为其的一个属性。 2.双向关联,就是说将对方()当做自己的一个属性。例如顾客与商品的关系...
  • 方法一:在对象属性上添加注解@JSONField(serialize=false)//转换成json的时候去除subareas属性 private Set subareas = new HashSet(0);方法二:使用参数过滤器//方法二:通过fastjson的参数过滤器将任何一个bean...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 533,817
精华内容 213,526
关键字:

关联类的属性