1 / 33

第七讲:类型层次规格与迭代抽象

第七讲:类型层次规格与迭代抽象. 吴际 2014-4-25. 本讲提纲. 回顾类型层次 子 类与父类的关系 集合元素 的 迭代访问 作业. 回顾类型层次. 类型 数据及其操作的规格化 0001 --> ( boolean )true; (integer)1;… 在 OO 范畴下,规格化的不只是数据解析,还包括对数据的处理 例:对集合有哪些处理? 类型层次是一种对数据及其处理的系统化抽象结果 逐 层往上抽取共性特征 逐 层往下增强细节描述能力 例子? 在 Java 语言中通过继承机制来定义类型层次. 回顾类型层次. 继承本质上是扩充 + 扩展

latham
Download Presentation

第七讲:类型层次规格与迭代抽象

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第七讲:类型层次规格与迭代抽象 吴际 2014-4-25

  2. 本讲提纲 • 回顾类型层次 • 子类与父类的关系 • 集合元素的迭代访问 • 作业

  3. 回顾类型层次 • 类型 • 数据及其操作的规格化 • 0001 --> (boolean)true; (integer)1;… • 在OO范畴下,规格化的不只是数据解析,还包括对数据的处理 • 例:对集合有哪些处理? • 类型层次是一种对数据及其处理的系统化抽象结果 • 逐层往上抽取共性特征 • 逐层往下增强细节描述能力 • 例子? • 在Java语言中通过继承机制来定义类型层次

  4. 回顾类型层次 • 继承本质上是扩充+扩展 • 扩充:增加新的属性和操作 • 扩展:重写(override)已有的操作 • 继承机制并不总能得到有效的类型层次 • 给定集合类Set,继承出CourseList类==》具有类型层次吗? • 替换原则 • 在任何父类型对象出现的地方使用子类对象都不会破坏使用程序的行为

  5. 回顾类型层次 • Poly p1 = new DensePoly(); • Poly p2 = new SparsePoly(4,50); • p1,p2的声明类型为Poly,实际类型却分别是DensePoly, SparsePoly • 使用instanceof操作符来判断一个对象的实际类型 • Java定义类型层次的手段 • extends

  6. 类型层次设计 • 子类继承了父类的规格 • 子类可以重写父类的部分过程规格 • 子类可以扩充父类的过程规格和数据规格 • 子类的rep:父类rep+子类增加的rep • 子类对象对父类属性变量的访问控制问题! • 为了满足类型层次的可替换性 • 子类重写或重载父类的方法时不能违背其规格 • 构造函数规格 • 首先要调用父类构造函数super.A(…)来初始化父类所定义的属性变量 public class A{ public int find(T x) throws NotFoundException //modifies: none //effects: returns the index where x is stored, //otherwise throws NotFoundException public class B2{ public int find(T x) throws NotFoundException //modifies: this //effects: returns the index where x is stored //and records x, otherwise throws //NotFoundException public class B3{ public int find(T x) throws SomeException //modifies: none //effects: returns the index where x is //stored, otherwise returns SomeException public class B1{ public int find(T x) throws NotFoundException //modifies: none //effects: returns the index where x is stored, //otherwise returns -1

  7. 类型层次设计 • 子类可以重写父类的方法,但需要保持父类的方法规格仍然成立 • publicclassIntSet { • //OVERVIEW: IntSets are mutable, unbounded sets of integers. A typical IntSetis{x1, .. ,xn}. • publicIntSet ( ) • //EFFECTS: Initializes this to be empty. • publicvoid insert (int x) • //MODIFIES: this • //EFFECTS: Adds x to the elements of this . • publicvoid remove (int x) • //MODIFIES: this • //EFFECTS: Removes x from this. • publicbooleanisln (int x) • //EFFECTS : If x is in this returns true else returns false. • publicint size ( ) • //EFFECTS: Returns the cardinality of this . • public Iterator elements ( ) • //EFFECTS: Returns a generator that produces all elements of this (as Integers), each exactly once, in arbitrary order. • //REQUIRES: this not be modified while the generator is in use. • publicboolean subset (IntSet s) • //EFFECTS: Returns true if this is a subset of s else returns false. • publicbooleanrepOk ( ) • } 基于IntSet规格,我们要定义MaxIntSet规格,该类在管理整数集合基础上,还能够管理集合中的最大数。 • publicclassMaxIntSetextendsIntSet{ • //OVERVIEW: MaxlntSet is a subtype of IntSet with an additional method, max, //to determine the maximum element of the set. • publicMaxlntSet ( ) • //EFFECTS: Makes this be the empty MaxIntSet. • publicint max ( ) throwsEmptyException • //EFFECTS :If this is empty throws EmptyException else returns the largest //element of this. • }

  8. 类型层次设计 • 子类的抽象函数 • 回顾: AF: CA, AF(c) = …, C为表示对象空间(即类型实现),A为抽象对象空间 • IntSet抽象函数 • 表示对象:Vector els • AF(c) = {c.els[i].intValue|0<=i<c.els.size} • MaxIntSet抽象函数 • 表示对象:(Vector els) int biggest • AF(c) = ? AF_MaxIntSet(c) = AF_IntSet(c)

  9. 类型层次设计 • 并不是所有的子类抽象函数都和父类一致 • IntSet,ComplexSet(复数集) • AF_IntSet(c) = {c.els[i].intValue|0<=i<c.els.size} • AF_ComplexSet(c) = (AF_IntSet(c), {c.mels[i].intValue|0<=i<c.mels.size}) • 子类与父类的表示不变式 • I_sub(c) implies I_super(c) • I_IntSet(c): c.els <> null && c.els[i] is an Integer for all 0<=i<c.els.size && c.els[i].intValue <> c.els[j].intValue for all 0<=i <j<=c.els.size • I_MaxIntSet(c): I_IntSet(c) && ((c.els.size > 0) (c.biggest >= c.els[i] for all 0<=i<c.els.size && k,0<=k<c.els.size, c.biggest = c.els[k].intValue)) 这里的c是MaxIntSet对象,不是IntSet对象,”c.els[i]”表示c可以直接访问IntSet中的els!

  10. 类型层次设计 • 子类与父类在不变式方面具有紧密的关联 • 子类的repOK应该调用父类的repOK来检查父类rep是否满足父类的不变式要求,并增加专属于子类的不变式检查逻辑 MaxIntSet{ public booleanrepOK(){ inti; boolean existed = false; if (!super.repOK())return false; for(inti=0;i<size();i++){ if(biggest < getAt(i)) return false; if(biggest == getAt(i)) existed = true; } if(i==0) return true; return existed; } } I_MaxIntSet(c): I_IntSet(c) && ((c.els.size > 0) (c.biggest >= c.els[i] for all 0<=i<c.els.size && k,0<=k<c.els.size, c.biggest = c.els[k].intValue))

  11. 类型层次的设计 • 子类型方法与父类型方法的关系 • 替换原则要求任何父类型对象出现的地方都可以使用子类型对象来替换 • Requires_superimpliesRequires_sub • 替换原则要求任何子类型对象的方法调用都能够满足父类型在相应方法的规格 • (Requires_super && Effects_sub) impliesEffects_super • 在父类型的前置条件不满足时,父类型方法就不会进行处理;但是子类型方法可能进行处理 • 子类型方法可以减弱父类型方法规定的Requires,或者加强父类型方法规定的Effects • 对比分析IntSet的insert方法和MaxIntSet的insert方法 • Requires: IntSet.insert(x) ---(none, i.e. true); MaxIntSet.insert(x)---(?) • Effects: IntSet.insert(x) --- (adds x into this); MaxIntSet.insert(x) ---(?) (adds x into this && biggest = x if x>biggest)?

  12. 类型层次的设计 • 在设计类型层次时,必须要考虑未来的扩展能力 • 类型层次的细化可能发生在未来 • 类型层次的细化可能由别人来做 • 必须注意父类型是否具有对未来子类型的概括能力 • 否则,一旦引入子类型,就可能会导致user code修改 • 但是,user code的修改代价可能非常高! public class Animal{ … } public class Some{ public void action (Animal a){ … if(a instanceof Fish) (Fish)a.swim(); if(a instanceofSwan) (Swan)a.fly(); … } } 建立动物的层次抽象,要求针对动物的具体能力提供相应的行为操作,使得用户可以调用相应的操作以模拟动物的能力。 public class Fish{ public ** swim(…){} } public class Swan{ public ** fly(…){} }

  13. 类型层次下的正确性证明问题 • 类正确性 • 对象状态有效性 • 类方法实现满足其规格要求 • 类型层次下的正确性论证思路 • 基类的正确性论证 • 子类对象的有效性论证 • 子类新增方法的正确性论证 • 子类重写方法的正确性论证

  14. 类型层次下的正确性证明问题 • 子类对象有效性论证 • 重用父类对象的有效性论证 • 构造器不会导致父类rep无效 • 构造器保证子类新定义rep有效 • 针对所有子类更新方法 • 如果更新了父类rep,需要证明不会导致父类rep无效 • 如果更新了子类rep,需要证明可以保持子类rep有效 • 如果子类不能直接操作父类的rep,则证明就会简洁许多 • 子类更新方法不可能直接更新父类rep • 只能调用父类方法来更新父类rep---->父类所有方法都被证明不会导致repOK为假!

  15. 类型层次下的正确性证明问题 • publicclassMaxIntSetextendsIntSet{ • //OVERVIEW: MaxlntSet is a subtype of IntSet with an additional method, max, to determine the maximum element of the set. • private int biggest; //holds the maximal integer in the set • publicMaxlntSet ( ){ • //EFFECTS: Makes this be the empty MaxIntSet. • super(); • biggest = Integer.MIN_VALUE; • } • publicint max ( ) throwsEmptyException{ • //EFFECTS :If this is empty throws EmptyException else returns the largest element of this. • if (this.size() ==0) throw EmptyException(“MaxInset:max”); • return biggest; • } • public void insert(int x){//Effects: adds x into this • super.insert(x); • if (x > biggest) biggest = x; • } • public void remove(int x){ //Effects: Removes x from this • super.remove(x); • inti,j; • biggest = Integer.MIN_VALUE; • for(i=0; i<size();i++){ • j = getAt(i); • if (j > biggest) biggest = j; • } • } • } • 子类重写方法的正确性论证 • 子类重写方法的规格蕴含父类方法规格 • 子类方法的实现满足其规格 请设计其论证思路

  16. 集合元素的迭代访问 • 使用类来封装和管理数据 • 集合是一类重要的数据封装和管理类型 • 所有程序几乎都涉及 • 具有动态性 • 实现方式多样化:Array, Vector, List, HashSet, Tree, Graph,… • 集合类型的操作 • 查看操作:元素个数、是否为空、是否存在某个元素、定位某个元素、查找某个元素… • 更新操作:排序、插入、删除、重复排除… • User的期望 • 管理集合 • 遍历集合元素进行特定的处理(User的业务逻辑) 找出MaxIntSet中与中值相差不超过半径r的所有元素

  17. 集合元素的迭代访问 • 方法1:无保护访问 • 直接把一个对象的内部rep返回给用户进行操作 • 对象自己无法控制rep状态,会导致invariant不能满足 • 例:对IntSet元素求和 • 方法2:有保护的克隆访问 • 直接返回对象rep的克隆,对象数据得到保护 • 缺点:? • 方法3:不规范的有保护访问 • 获得集合元素个数 • 循环调用查找操作来获得相关的元素 • for(i=0;i<o.size();i++){…;o.get(i)…} • 例:为IntSet增加getAt(int index)方法 • 讨论:每个集合类型都要提供类似的方法,是否可以规范化? • 方法4:规范的有保护访问(迭代抽象机制)

  18. 集合元素的迭代访问 • 迭代抽象机制 • 通过模板化的迭代器接口规范元素访问 • hasNext()判断是否还有元素来迭代访问 • next()返回下一个元素 • 一次只返回一个元素 • 有状态访问(stateful iteration) for each result item i produced by Iterator A do something with i • publicinterface Iterator<E>{ • publicbooleanhasNext ( ); • //EFFECTS: Returns true if there are more elements to yield else returns false • public E next ( ) throwsNoSuchElementException; • //MODIFIES: this • //EFFECTS: if there are more results to yield, returns the next result • //and modifies the state of this to record the yield. • //Otherwise, throws NoSuchElementException • } booleanhasNext() Collective Class Iterator<E> E next()

  19. 集合元素的迭代访问 • Java提供的Iterator接口定义了三个操作 public Interface Iterator { public booleanhasNext(); public Object next() throws NoSuchElementException; public void remove() throws IllegalStateException, UnsupportedOperationException; }

  20. 定义 • 集合类型需要提供一个迭代器(iterator)方法来返回一个生成器(generator) • 一个集合类型可以定义多个迭代器方法来提供多个生成器 • 生成器的类型为Iterator • 生成器是一个能够以迭代方式生成相应元素的对象,它实现了Iterator 接口 • 迭代器方法的规格定义生成器的行为,生成器的规格则遵循Iterator 接口规格,无需再次定义。

  21. 示例:Poly and IntSet public class Poly { public Iterator terms() //Effects: Returns a generator that will produce exponents //of nonzero terms of this (as Integers) up to the degree, in order of increasing exponent } public class IntSet { public Iterator elements() // Requires: this must not be modified while the generator is in use // Effects: Returns a generator that will produce all the elements // of this (as Integers) each exactly once, in arbitrary order }

  22. 迭代访问的状态变化 Poly p … // p = 2 + 3 x2+ 4 x5 Iterator itr= p.terms(); // itr= [0,2,5] itr.hasNext() // return true, itr = [0,2,5] itr.next() // return 0, itr = [2,5] itr.next() // return 2, itr = [5] itr.hasNext() // return true, itr = [5] itr.next() // return 5, itr = [] itr.hasNext() // return false, itr = [] itr.next() // throw NoSuchElementException, itr = []

  23. 生成器的抽象函数和不变式 • 生成器本身是一个数据抽象,提供了hasNext和next操作来访问其管理的数据 • Poly类生成器的表示对象rep • private Poly p; //the Poly being iterated • private int n; //the next element to consider • Poly类的生成器 • AF(c) = [x1,…,xm] such that each xi is an integer, every index i>=c.n of a nonzero element of c.p.trms is in the sequence, and no other elements are in the sequence, and xi>xj for all i>j>=1. • I(c) = c.p <> null && (0 <= c.n <= c.p.deg)

  24. Poly生成器抽象函数在运行时的变化 Poly p … // p = 2 + 3 x2+ 4 x5 AF(itr.hasNext()) = [0,2,5] AF(itr.next()) = [2,5] AF(itr.next()) = [5] AF(itr.hasNext()) = [5] AF(itr.next()) = [] AF(itr.hasNext()) = [] AF(itr.next()) = []

  25. 生成器的实现 public booleanhasNext() {return n<= p.deg;} public Object next () throws NSEE{ for(int e = n; e <= p.deg; e++) { if (p.trms[e] != 0) { n= e+1; return new Integer(e); } } throw new NSEE(“Poly.terms”); } // end PolyGen } public class Poly{ // Rep … public Iterator terms() {return new PolyGen(this);} // inner class private static class PolyGenimplements Iterator { private Poly p; // the Poly being iterated private int n; // the next term to consider PolyGen(Poly it){ //Requires: it !=null p = it; if(p.trms[0] == 0) n=1; else n= 0; } private? static? Inner class?

  26. 课堂练习 public Interface TwoWayIterator { Object next (); Object previous (); booleanhasNext(); booleanhasPrevious(); } • 请写出TwoWayIterator的规格 • 假设把TwoWayIterator用于IntSet,请写出其抽象函数和不变式

  27. 如果你想支持remove操作 void remove() //optional operation Removes from the underlying collection the last element returned by this iterator.This method can be called only once per call to next(). The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method. Throws: UnsupportedOperationException- if the remove operation is not supported by this iterator IllegalStateException- if the next method has not yet been called, or the remove method has already been called after the last call to the next method AF(itr) = {1,2,3,5,10} AF(set) = {1,2,3,5,10} itr.next() ----1 AF(itr) = {2,3,5,10} AF(set) = {1,2,3,5,10} itr.remove () AF(set) = {1,2,5,10} AF(itr) = {2,3,5,10} set itr {1,2,3,5,10} {1,2,3,5,10},n=1

  28. 如果你想支持remove操作 • Step 1: 确保remove操作时集合类对象处于保护状态 • Think about multithreading • Step 2: 确保集合类提供remove指定对象的方法 • 如PolyGen中的Poly对象必须提供remove(int d)方法 • Step 3: 确保生成器记录next,remove的调用状态 • next() ----- nextStatus = true; removeStatus = false; • remove() -----nextStatus = false; removeStatus = true; • Step 4: 记录next生成的对象 • next() ---- justGenerated = …; return justGenerated; • Step 5: 确保生成器对remove操作进行控制 • if(nextStatus == false || removeStatus == true) return; • Lock(collection); • Collection.remove(justGenerated)

  29. 更加简便的迭代支持 http://blog.dreasgrech.com/2010/03/javas-iterators-and-iterables.html

  30. 作业 • 密室通讯游戏 • 一个密室有若干通讯工具,可分为三类:信号发生器、信号中转器、信号接收器,每个工具都有唯一可寻址的编码 • 信号发生器与信号接收器只能与信号中转器相连 • 信号中转器可以与多个信号中转器、发生器或接收器连接 • 每个信号中转器记录一系列中转规则 • 中转器在转发的信号中添加自己的ID号 • 每个信号中包含的数据为(sender, receiver, text, tlist),tlist为中转器ID列表 • 信号发生器包括明文发生器和密文发生器,加密规则是把明文text倒序 • 信号接收器包括明文接收器和密文接收器,解密规则是把密文text倒序

  31. 作业 • 密室通讯工具配置 • 只能有一个接收器,可有多个不同类型的发生器 • 可以有不超过6个中转器,且配置有中转规则 ”(tr1, tr2, tr3…), [receiver]” • 如果”[]”中的receiver无效或者为空,则表示中转器未连接有效的接收器 • (tr1,tr2,tr3…)为连接的中转器ID号,以逗号分隔,可出现0到多个 • 程序功能要求 • 根据所提供的密室通讯工具及其规则配置组织通讯网络 • 针对输入的消息文本,通讯网络能够使用发生器发出相应的信号,并被接收器收到

  32. 作业 • 作业要求 • 命令行提供密室通讯配置数据文件位置 • 程序运行打开配置文件,构造通讯工具对象和密室对象 • 程序模拟访问者与密室交互,并组装网络 • 程序在命令行输出网络拓扑结构 • 程序提示用户输入消息text,接收器命令行输出接收到的信号完整数据 • 作业必须说明自己采用的配置文件格式,便于他人测试 • 要求设计类型层次,并设计类规格和迭代规格 • 要求针对通讯工具类进行正确性论证 • 要求针对功能进行执行测试 • 要求对设计准则、规格书写的规范性和正确性论证进行检查

  33. 作业 • 访问者与密室的会话 • 你有多少通讯工具供我使用? • ---x • 你有哪几个信号发生器? • ---S1(能力),… • 你有哪些中装器可供使用? • ----T1(中转规则),… • 你有哪些接收器可供使用? • ---R1(能力),… • 我选择S2, R1, R3, Rx,T2 • 请帮我连S2到R1,R1,R3和Rx之间建立全连接,T2连接到Rx • 请帮我检查网络的连通性 • ---如果连通性ok,密室输出网络拓扑结构 • 密室:请使用S1发送消息 • ---hhhdaoof • 密室反馈收到的消息 • 密室:would you tell me something more? ---Y:继续通讯,N:执行结束。

More Related