切尔斯基

冰河洗剑,绝塞传烽,江山如画雪初晴

切尔斯基
切尔斯基的公告
质疑暂停, 发些以前的外传
最近评论
Jack:比喻很恰当,呵呵.
suxiaoguai:敏捷有好处也有短板:
==================
如果结对的双方没有类似的知识结构,效率一定不会高。这种情况下双方之间更多的是思想上的摩擦和相互学习,不是合作解决实际问题。结对需要长时间的前期投入才能开始起作用。
==================
这是个问题,所以敏捷一定需要有公司支持这个土壤。
另外团队的文化非常重要,
hachenzhonghua:结伴比较难。
这个对企业整体文化、管理能力要求比较高。
心胸坦荡的人并不多。落井下石的人却总是不缺
iceheart:你跟某人适合xp跟另外一些人不见得适合,某个项目适合xp另外的项目不见得适合,某些环境适合xp另外的不见得适合。

脱离了具体情况的空谈都是没有意义的争论
Eric:敏捷开发,纯粹扯淡!
前期开发者,写代码,写的很爽很惬意,进度相当快。
如果前期开发者离去,或者转投别的任务。
后期开发者,和同期的开发同伴,对已有的代码,简直牛啃南瓜,开不了头。
========================
这是质量控制体系有问题,没有code review?没有QA?没有相应的文档?
如果把前期的开发分成几……
文章分类
    收藏
      相册
      切尔分站
      切尔斯基的工作(RSS)
      切尔斯基的工具(RSS)
      切尔斯基的杂记(RSS)
      亲密爱人
      丸子(RSS)
      文学艺术
      芳村窝蛋(RSS)
      存档
      订阅我的博客
      XML聚合  FeedSky

      原创 对象语义与值语义收藏

      新一篇: Ruminations on C++ | 旧一篇: Essential SICP Primer

      一、值语义

      • 所谓值语义是一个对象被系统标准的复制方式复制后,与被复制的对象之间毫无关系,可以彼此独立改变互不影响

      实现

       

      C++

      Java

      标准复制方式

      赋值、拷贝构造

      赋值,clone()

      基本数据类型

      包括整数,浮点数,布尔值,字符,指针等,全部为值语义

      包括整数,浮点数,布尔值,字符等,全部为值语义

      自定义类型

      不包含资源的自定义类型,系统提供的缺省拷贝构造函数与赋值操作符亦保证了值语义;包含资源的自定义类型,需要提供深拷贝操作的拷贝构造函数和赋值操作符,并在构造函数中获取资源,在析构函数中释放资源

      没有十分自然的方式将Java对象实现为值语义,通常采用“不可变类”的方式,如String,或递归实现深度clone()

      优点

      • 避免别名问题导致的意外修改

      • 避免对共享资源的引用引起的释放时机和额外的引用计数问题

      缺点

      • 占用较多内存

      应用

      • 通常将具有“等价性”的对象实现为值语义,如Money,你的10块钱跟我的10块钱没什么两样,完全可以换过来用

      举例

      C++

      Java

      vector<int> first;

      vector<int> second = first;

      second.push_back(1000);

      cout << first.size(); //0

      cout << second.size();//1

      String first = "abc";

      String second = first;

      first = first.replace('a', 'x');

      System.out.println(first); //xbc

      System.out.println(second);//abc 

       

      二、对象语义

      • 也叫指针语义,引用语义等,通常是指一个对象被系统标准的复制方式复制后,与被复制的对象之间依然共享底层资源,对任何一个的改变都将改变另一个

      实现

       

      C++

      Java

      标准复制方式

      赋值、拷贝构造

      赋值,clone()

      自定义类型

      包含资源的自定义类型,没有提供拷贝构造函数和赋值操作符,或者在拷贝构造函数和赋值操作符中有意共享资源,则此时的对象具有指针语义

      缺省全为指针语义,除非该类及其成员递归实现深度clone(),或实现为“不可变类”

      优点

      • 占用较少内存

      缺点

      • 别名问题导致的意外修改,尤其应主意用于模块间接口的参数和返回值

      • 资源释放的额外负担,通常是引用计数

      应用

      • 通常将必须保持“同一性”的对象实现为对象语义,如帐户,虽然你的帐户和我的帐户此时都只剩100块钱了,但你的是你的,我的是我的,将来你发了财也只会存到你帐户上;具有“同一性”的对象通常在系统中有唯一ID,这类对象通常不可复制,因为复制没有现实意义,如网络端口,数据库链接

      举例

      C++

      Java

      vector<int> obj(2, 0);

      vector<int>::iterator first = obj.begin();

      vector<int>::iterator second = first;

      cout << *first; //0

      cout << *second;//0

      *first = 1;

      cout << *first; //1

      cout << *second;//1

      List<Integer> first = new ArrayList<Integer>();

      List<Integer> second = first;

      second.add(1000);

      System.out.println(first.size()); //1

      System.out.println(second.size());//1

       

      注:

      1. 即使在具有垃圾回收的系统中,资源释放依然是个问题,因为资源不止内存,还有网络端口,数据库链接等

      2. 同一与等价的问题,可参见<<Structure and Interpretation of Computer Programs>>笔记

      3. 录一篇 wangtianxing 老师的观点,比我说的清楚有趣的多:

      我认为“值”与“对象”的区分在设计和实现时具有非常重要的指导作用,
      因此下面做一些说明。

      “值”与“对象”类型之间并没有严格定义的区分。但通常可以观察到下列不同:

      0. “值”是“死的”、“傻的”、“简单的”、“具体的”、“可复制的”,
      “对象”是“活的”、“聪明的”、“复杂的”、“抽象的”、“不可复制的”。

      这里的“复杂性”主要还是指行为的复杂性,而非结构的复杂性。例如,

      list< map< vector<string>, deque< set<int> > > >

      仍然是一个不折不扣的“值”类型。

      这里我们不在哲学的路上走太远,还是看看下面更具体的一些特征吧。

      1. “值”的成员函数(包括解构函数)都不是 virtual 的,不是设计来被继承的。
      “对象”的解构函数是 virtual 的,而且通常还有其它的 virtual 成员函数,
      是设计来被继承的,或继承了其他基类。

      // value:
      struct String {
      // non-virtual destructor:
      ~String() { delete[] s_; }
      private:
      char* s_;
      };

      // string should not be public-ly inherited.

      // object:
      struct OutputDevice {
      virtual ~OutputDevice();
      virtual void output( char const* ) = 0;
      };

      struct ConsoleOutputDevice : OutputDevice {
      // inherits virtual destructor,
      // overrides virtual member function:
      void output( char const* );
      };

      2. “对象”经常必须通过指针或引用来使用,“值”不一定需要。

      ::std::auto_ptr<OutputDevice> output( new ConsoleOutputDevice() );

      void f( OutputDevice& dev )
      {
      // ...
      dev.output( "blah blah\n" );
      // ...
      }

      String s = "dsjflsdjflsjlf";
      String t = "djslfdsjfsl";
      s += t;

      void g( String s ) // by-value is OK.
      {
      // ...
      }

      g( s );


      3. “值”可以复制出任意多份等价物,是 Assignable, CopyConstructible 的
      (C++标准里定义了Assignable, CopyConstructible 的具体含义)。
      “对象”通常不是 Assignable 也不是 CopyConstructible 的,通常是被共享的
      不是被复制的。 即使“对象”被“克隆”,“克隆”出来的对象与原对象也不是
      完全等价的:相同的基因,不同的个体。

      string s = "dsjlfsdjlfsdjlfsdjl";
      string t;
      t = s;
      // the following two lines are equivalent:
      cout << s;
      cout << t;

      auto_ptr<OutputDevice> dev1( new ConsoleOutputDevice(...) );
      auto_ptr<OutputDevice> dev2( dev1.clone() );
      // the following two lines are NOT equivalent:
      dev1->output( "blah blah" );
      dev2->output( "blah blah" );

      这里,dev2 可能具有与 dev1 相同的位置、大小、权限等属性,但却是
      完全不同的另一个窗口。

      4. 对于“值”类型,应该严格保证 constness-correctness,对于“对象”类型,
      通常不需要,甚至有些 'const' 是有害的。

      // bad design of a value type:
      struct Contact {
      string address(); // non-const
      };

      void f( Contact const& contact )
      {
      cout << contact.address(); // won't compile.
      }

      // maybe bad design of an intelligent object type:
      struct Robot {
      string name( Object const& asker ) const // const!
      { return my_name; }
      private:
      string my_name;
      };

      由于 Robot 的智能,问他一次名字也可能要触发它内部状态的改变。
      一般来说,我们不应该对一个复杂“对象”假设任何操作不改变其内部状态,
      因此其界面上不应有 const 成员函数。 使用一个 const Robot
      也是毫无意义的。如果你觉得 Robot 比较特殊,可以想想 const Database。

      5. “值”是可以比较的,“对象”通常是不可比较的,要比较的话,
      应该比较对象的地址,而不是内容。

      根据“值”类型表达的概念的特点,比较关系运算可分为两个层次:

      a 相等性比较:

      bool operator == ( T const& ) const;
      bool operator != ( T const& ) const
      { return ! operator == ( other ); }

      而且 operator !=( other ) 必须等价于 ! operator == ( other ),
      operator == () 必须是一个“等价关系”(equivalence relationship):
      任给 T a, b, c:

      (自反的) (a == a) => true.
      (对称的) (a == b) => (b == a).
      (传递的) (a == b && b == c) => (a == c).

      对于一个类型 T 的两个对象 a, b,如果表达式 (a == b) 可以转换为
      bool 类型,而且这个 operator == () 是 T 上的一个等价关系,那么
      就说 T 是 EqualityComparable 的。

      b 排序关系比较:

      bool operator < ( T const& ) const;
      bool operator > ( T const& other ) const
      { return other < *this; }
      bool operator >= ( T const& other ) const
      { return ! operator < ( other ); }
      bool operator <= ( T const& other ) const
      { return ! operator > ( other ); }

      这些运算之间的关系必须满足上面给出的实现所表达的等价性。
      (因此通常只实现 operator<(),然后从这里 copy 另外三个!)
      operator <() 必须是 T 上的一个“严格弱序”
      (strict weak ordering)关系:

      任给 T a, b, c:

      (irreflexive) (a < a) => false.
      (transitive) (a < b && b < c) => (a < c).
      (weak ordering)
      定义 eqiv(a,b) = ! (a < b) && ! (b < a).
      equiv(a,b) && equiv(b,c) => eqiv(a,c).

      这样,operator<() 可以在 equiv 决定的 T 的等价类上定义一个全序
      (total ordering).

      对于一个类型 T 的两个对象 a, b,如果表达式 (a < b) 可以转换为
      bool 类型,而且这个 operator < () 是 T 上的一个严格弱序关系,
      那么就说 T 是 LessThanComparable 的。

      一个“值”类型可以只实现相等性比较。如果同时实现了排序关系比较,
      那么必须有 (a == b) iff (! (a < b) && ! (b < a))。

      上述对关系运算的要求来自于 C++ 标准中对容器类中对象的要求。即使
      你的类型的对象不被放到标准容器中,也应该满足上述要求,否则就可能
      产生一些让他人吃惊的行为。

      综上所述,在设计一个类时,如果思考一下这个类表达的是一个简单的“值”
      还是一个复杂的“对象”,非常有助于决定类的界面以及用法的许多方面:

      . 会不会被继承/有没有 virtual 函数?
      . 是否允许拷贝和赋值?还是必须共享/克隆?
      . 如何对待 constness-correctness?
      . 是否应该实现比较运算?实现哪些?

      等等等等。

      (除了“值”和“对象”的区分外,还有一批C++中的类型可以归类为
      表达了一个“概念”,但那是另一个话题)

      "三月的外星人" <UFO@sina.com> 写入消息
      news:a8g76p$cb14@svr.novel.com...
      > 标准中一些具体的类是否都应当看作是“值”类,比如“map",list,vector等?
      > 而一些抽象的类就可以看成是”对象“类?

      标准的数据类型大致有以下几类:

      “值”:

      各种基本类型:int, double, ...。各种指针。complex<>。
      各种容器: vector<>, list<>, multi/set<>, multi/map<>, deque<>,
      bitset<>, basic_string<>, valarray<>... 以及它们的各种 iterator。
      adaptors: stack<>, queue<>, priority_queue<>。
      各种 functor: less, greater, equal_to, plus, minus, binder1st...。
      locale 是把“对象”类型通过共享方式包装成“值”类型,以方便使用。


      “对象”:

      iostream相关类:basic_ios<>, basic_*stream<>, basic_*streambuf<>。
      各种facet: ctype_base/ctype<>, codecvt_base/codecvt<>...。
      type_info。


      “值与对象的混合物”

      异常类:exception,bad_exception, logic_error, range_error...。
      可以象“值”一样复制,但又有继承层次,可以通过基类(exception)
      引用或指针来使用。这种设计在应用程序里最好避免,因为很容易引起
      object-slicing:

      exception e = domain_error( "sqrt(NegativeNumber)" );

      上面一行能编译,能运行,但没有做想让它做的事。


      “概念实现”:(象“值”一样简单,但不是用来装一个“值”的)

      iterator<>, input_iterator_tag, output_iterator_tag...,
      unary_function<>, binary_function<>...。


      “特征描述”

      iterator_traits<>, char_traits<>, numeric_limits<>...。


      “怪物”:

      auto_ptr<>。
       

      发表于 @ 2005年07月29日 15:20:00|评论(loading...)|编辑|收藏

      新一篇: Ruminations on C++ | 旧一篇: Essential SICP Primer

      评论:没有评论。

      发表评论  


      登录
      Csdn Blog version 3.1a
      Copyright © 切尔斯基