文韬's profile菠萝的天空PhotosBlogListsMore Tools Help

菠萝的天空

Photo 1 of 34
September 03

Closure

Martin Fowler    http://martinfowler.com/bliki/Closure.html

Closure

design 8 September 2004 Reactions

As there is a growing interest in dynamic languages, more people are running into a programming concept called Closures or Blocks. People from a C/C++/Java/C# language background don't have closures and as a result aren't sure what they are. Here's a brief explanation, those who have done a decent amount of programming in languages that have them won't find this interesting.

Closures have been around for a long time. I ran into them properly for the first time in Smalltalk where they're called Blocks. Lisp uses them heavily. They're also present in the Ruby scripting language - and are a major reason why many rubyists like using Ruby for scripting.

Essentially a closure is a block of code that can be passed as an argument to a function call. I'll illustrate this with a simple example. Imagine I have a list of employee objects and I want a list of those employees who are managers, which I determine with an IsManager property. Using C#, I'd probably write it like this.

  public static IList Managers(IList emps) {
    IList result = new ArrayList();
    foreach(Employee e in emps)
      if (e.IsManager) result.Add(e);
    return result;
  }

In a language that has Closures, in this case Ruby, I'd write this.

def managers(emps)
  return emps.select {|e| e.isManager}
end
  

Essentially select is a method defined on the Ruby collection class. It takes a block of code, a closure, as an argument. In ruby you write that block of code between curlies (not the only way). If the block of code takes any arguments you declare those between the vertical bars. What select does is iterate through the input array, executes the block of code with each element, and returns an array of those elements for which the block evaluated as true.

Now if you're a C programmer you probably think "I could do that with a function pointer", if you're a Java programmer you probably think "I could do that with an anonymous inner class", a C#er would consider a delegate. These mechanisms are similar to closures, but there are two telling differences.

The first one is a formal difference, closures can refer to variables visible at the time they were defined. Consider this method

def highPaid(emps)
  threshold = 150
  return emps.select {|e| e.salary > threshold}
end
  

Notice that the code in the select block is referring to a local variable defined in the enclosing method. Many of the alternatives to closures in languages that don't have real closures can't do that. Closures allow you to do even more interesting stuff. Consider this function.

def paidMore(amount)
  return Proc.new {|e| e.salary > amount}
end

This function returns a closure, indeed it returns a closure whose behavior depends on the argument sent into it. I can create such a function with and assign it to a variable.

highPaid = paidMore(150)

The variable highPaid contains a block of code (called a Proc in Ruby) that will return whether a tested object has a salary greater than 150. I might use it like this.

john = Employee.new
john.salary = 200
print highPaid.call(john)
  

The expression highPaid.call(john) calls the e.salary > amount code I defined earlier, with the amount variable in that code bound the to the 150 I passed in when I created the proc object. Even if that 150 value went out of scope when I issue the print call, the binding still remains.

So the first crucial point about closures is that they are a block of code plus the bindings to the environment they came from. This is the formal thing that sets closures apart from function pointers and similar techniques.(Java's anonymous inner classes can access locals - but only if they are final.)

The second difference is less of a defined formal difference, but is just as important, if not more so in practice. Languages that support closures allow you to define them with very little syntax. While this might not seem an important point, I believe it's crucial - it's the key to make it natural to use them frequently. Look at Lisp, Smalltalk, or Ruby code and you'll see closures all over the place - much more frequently used than the similar structures in other languages. The ability to bind to local variables is part of that, but I think the biggest reason is that the notation to use them is simple and clear.

A good case in point is what happened when ex-Smalltalkers started in Java. Initially many people, including me, experimented with using anonymous inner classes to do many of things that we'd done with blocks in smalltalk. But the resulting code was just too messy and ugly so we gave up.

Like any term in software there is a lot of blur about the exact definition of closure. Some people say that the term only applies to an actual value that includes bindings from its environment, such as the value returned by highPaid. Others use the term 'closure' to refer to a programming construct that has the ability to bind to its environment. This debate, an example of the TypeInstanceHomonym, is usually carried out with the politeness and lack of pedantry that our profession is known for.

I use closures a lot in Ruby, but I don't tend to create Procs and pass them around. Most of the time my use of closures is based around CollectionClosureMethods similar to the select method I showed earlier. Another common use is the 'execute around method', such as when processing a file.

File.open(filename) {|f| doSomethingWithFile(f)}

Here the open method opens the file, executes the supplied block, and then closes it. This can be a very handy idiom for things like transactions (remember to commit or rollback) or indeed anything where you have to remember to do something at the end. I use this extensively in my xml transformation routines.

Such use of closures is actually much less than what people in the Lisp and functional programming worlds do. But even with my limited uses I miss them a lot when programming in languages without them. They are one of those things that seem minor when you first come across them, but you quickly grow to like them.

March 19

Moonlight Shadow

The last that ever she saw him carried away by a moonlight shadow
He passed on worried and warning carried away by a moonlight shadow
Lost in a river last saturday night far away on the other side
He was caught in the middle of a desperate fight
And she couldn't find how to push through

The trees that whisper in the evening carried away by a moonlight shadow
Sing a song of sorrow and grieving carried away by a moonlight shadow
All she saw was a silhouette of a gun far away on the other side
He was shot six times by a man on the run
And she couldn't find how to push through

I stay, I pray, I see you in heaven far away
I stay, I pray, I see you in heaven one day

Four A.M. in the morning carried away by a moonlight shadow
I watched your vision forming carried away by a moonlight shadow
Stars moved slowly in a silvery night far away on the other side
Will you come to talk to me this night?
But she couldn't find how to push through

I stay, I pray, I see you in heaven far away
I stay, I pray, I see you in heaven one day

Caught in the middle of a hundred and five
The night was heavy and the air was alive
But she couldn't find how to push through
Far away on the other side. The night was heavy and the air was alive
But she couldn't find how to push through
She couldn't find how to push through, how to push through (Repeat)
October 22

2007年10月20日,HO1120,成都至上海的航班上

     2007年10月20日,HO1120,成都至上海的航班上
     今天终于离开了生我养我的家乡-四川,23年了,第一次离开四川去寻找属于自己的世界,一直以来我都认为我是生性好动的,讨厌平淡安逸的生活,喜欢漂泊与挑战,就像每年的旅行一样,期望去发现能刺激我的元素。记得八年前当我第一次来到上海时,那天的天很蓝,蓝的超出了我的想象(四川盆地感觉随时都是雾蒙蒙的,特别是成都),蓝天下整个现代化的都市使我相当震撼,繁华、高节奏、竞争与机会,充满了那么多能刺激我的元素,那时我就知道总有一天我会回到这里的。从高考的失败,到毕业后的犹豫,今天我终于决定出发了,1800公里,2小时40分钟的航程,我的人生一定会从今天开始改变。
     现在飞机是不是在绝恋妹妹生活的城市上空喃?嘿嘿
     一直以来都想离开成都,但是当今天真正离开时,我发现还是很舍不得,熟悉的街道、亲人、朋友,还有我深爱的人,这一切都将远离,今天家人给我送别时我发现我居然有点想哭的冲动,o(∩_∩)o...还好拒绝了所有朋友的送别,不然真的哭了就丢脸了。其实时间还是过的蛮快的,都已在成电工作一年了,当时应聘成电时的场景都还历历在目,7个部门领导的面试感觉就像在审犯人一样,当然袁主任还是那么的和蔼、有魅力,:-)。在成电一年收获还是蛮大的,认识了一些朋友,关键还有电信小妹哦,^_^
     还有20分钟就要到上海了,本来还有很多要写的,只有等下飞机后继续了,飞机即将降落,我的梦想即将起飞,fighting,nothing is impossible.
March 22

add sequence

interface Selector {
   boolean end();
   object current();
   void next();
}
 
public class Sequence
   private Object[] obs;
   private int next=0;
   public Sequence(int size){
       obs=new object[size];
   }
   public void add(object x) {
       if(next < obs.lenght) {
          obs[next] = x;
          next++;
          }
   }
   private class SSelector implements Selector {
      int i = 0;
      public boolean end() {
          return i == obs.lenght;
      }
      public object current() {
          return obs[i];
      }
      public void next() {
         if(i < obs.lenght) i++;
      }
   }
 
   public Selector getSelector() {
       return new SSelector();
   }
   public static void main(String[] args) {
      Sequence s = new Sequence(10);
      for(int i = 0; i<10 ; i++)
         s.add(Integer.toString(i));
      Selector sl = s.getSelector();
      while(!sl.end()) {
          System.out.println(sl.current());
          sl.next();
      }
   }
}

Hibernate

Hibernate是一个免费的开源Java包,它使得与关系数据库打交道变得十分轻松,就像您的数据库中包含每天使用的普通Java对象一样,同时不必考虑如何把它们从神秘的数据库表中取出(或放回到数据库表中)。它解放了您,使您可以专注于应用程序的对象和功能,而不必担心如何保存它们或稍后如何找到它们。
  
  大多数应用程序都需要处理数据。Java应用程序运行时,往往把数据封装为相互连接的对象网络,但是当程序结束时,这些对象就会消失在一团逻辑中,所以需要有一些保存它们的方法。有时候,甚至在编写应用程序之前,数据就已经存在了,所以需要有读入它们和将其表示为对象的方法。手动编写代码来执行这些任务不仅单调乏味、易于出错,而且会占用整个应用程序的很大一部分开发工作量。
  
  优秀的面向对象开发人员厌倦了这种重复性的劳动,他们开始采用通常的“积极”偷懒做法,即,创建工具,使整个过程自动化。对于关系数据库来说,这种努力的最大成果就是对象/关系映射(ORM)工具。
  
  这类工具有很多,从昂贵的商业产品到内置于J2EE中的EJB标准。然而,在很多情况下,这些工具具有自身的复杂性,使得开发人员必须学习使用它们的详细规则,并修改组成应用程序的类以满足映射系统的需要。由于这些工具为应付更加严格和复杂的企业需求而不断发展,于是在比较简单和常见的场景中,使用它们所面临的复杂性反而盖过了所能获得的好处。这引起了一场革命,促进了轻量级解决方案的出现,而Hibernate就是这样的一个例子。
  
  Hibernate的工作方式
  
  Hibernate不会对您造成妨碍,也不会强迫您修改对象的行为方式。它们不需要实现任何不可思议的接口以便能够持续存在。惟一需要做的就是创建一份XML“映射文档”,告诉Hibernate您希望能够保存在数据库中的类,以及它们如何关联到该数据库中的表和列,然后就可以要求它以对象的形式获取数据,或者把对象保存为数据。与其他解决方案相比,它几乎已经很完美了。
  
  由于本文只是一篇介绍性的文章,所以不会引入构建和使用Hibernate映射文档的具体例子(我在《Hibernate: A Developer's Notebook》一书的头几章中已经介绍了一个例子)。此外,在网上和Hibernate的在线文档中,还可以找到一些不错的例子,请参见下面的“其他信息”部分。它实际上相当直观。应用程序对象中的属性以一种简单而自然的方式与正确的数据库结构相关联。
  
  运行时,Hibernate读取映射文档,然后动态构建Java类,以便管理数据库与Java之间的转换。在Hibernate中有一个简单而直观的API,用于对数据库所表示的对象执行查询。要修改这些对象,(一般情况下)只需在程序中与它们进行交互,然后告诉Hibernate保存修改即可。类似地,创建新对象也很简单;只需以常规方式创建它们,然后告诉Hibernate有关它们的信息,这样就能在数据库中保存它们。
  
  Hibernate API学习起来很简单,而且它与程序流的交互相当自然。在适当的位置调用它,就可以达成目的。它带来了很多自动化和代码节省方面的好处,所以花一点时间学习它是值得的。而且还可以获得另一个好处,即代码不用关心要使用的数据库种类(否则的话甚至必须知道)。我所在的公司就曾有过在开发过程后期被迫更换数据库厂商的经历。这会造成巨大的灾难,但是借助于Hibernate,只需要简单地修改Hibernate配置文件即可。
  
  这里的讨论假定您已经通过创建Hibernate映射文档,建立了一个关系数据库,并且拥有要映射的Java类。有一个Hibernate“工具集”可在编译时使用,以支持不同的工作流。例如,如果您已经拥有Java类和映射文档,Hibernate可以为您创建(或更新)必需的数据库表。或者,仅仅从映射文档开始,Hibernate也能够生成数据类。或者,它可以反向设计您的数据库和类,从而拟定映射文档。还有一些用于Eclipse的alpha 插件,它们可以在IDE中提供智能的编辑支持以及对这些工具的图形访问。
  
  如果您使用的是Hibernate 2环境,这些工具鲜有提供,但是存在可用的第三方工具。
  
  使用Hibernate的场合
  
  既然Hibernate看起来如此灵活好用,为什么还要使用其他的工具呢?下面有一些场景,可以帮助您做出判断(或许通过提供一些比较和上下文,可以有助于鉴别非常适用Hibernate的场合)。
  
  如果应用对于数据存储的需要十分简单??例如,您只想管理一组用户优先选择??您根本不需要数据库,更不用说一个优秀的对象-关系映射系统了(即使它也如Hibernate这般易于使用)!从Java 1.4开始,有一个标准的Java Preferences API可以很好地发挥这个作用。(在ONJava文章中可以找到有关Preferences API的更多信息。)
  
  对于熟悉使用关系数据库和了解如何执行完美的SQL查询与企业数据库交互的人来说,Hibernate似乎有些碍手碍脚,这就像带有动力和自动排挡的快艇车会使注重性能的赛车驾驶员不耐烦一样。如果您属于这种人,如果您所在的项目团队拥有一个强大的DBA,或者有一些存储过程要处理,您可能想研究一下iBATIS。Hibernate的创建者本身就把iBATIS当作是另一种有趣的选择。我对它很有兴趣,因为我们曾为一个电子商务站点开发了一个类似的系统(其功能更为强大),而且从那时到现在,我们已经在其他环境中使用过它,尽管在发现Hibernate之后,在新项目中我们通常更喜欢使用Hibernate。您可以认为,以SQL为中心的解决方案(比如iBATIS)是“反向的”对象/关系映射工具,而Hibernate是一个更为传统的ORM。
  
  当然,还有其他的外部原因会导致采用另外的方法。比如,在一个企业环境中,必须使用成熟的EJB架构(或者其他的一些非普通对象映射系统)。可以为提供自己的数据存储工具的平台量身定做代码,比如Mac OS X's Core Data。使用的可能是像XML DTD这样的存储规范,而它根本不涉及关系数据库。
  
  但是,如果您使用的是富对象模型,而且想要灵活、轻松且高效地保存它(无论您是否正要开始或已经决定使用关系数据库,只要这是一个选择??而且存在可用的优秀免费数据库,比如MySQL,或可嵌入Java的HSQLDB,它就应该始终是一个选择),那么Hibernate很可能就是您理想的选择。您可能会惊讶于节省的时间之多,以及您将会多么地喜欢使用它。
  
  其他信息
  
  Hibernate项目有大量的在线文档,可以帮助您找准方向,快速开始使用。
  
  权威性的参考资料是Hibernate in Action,作者是Christian Bauer和Gavin King,都是Hibernate的创建者。该书全面而基础地讲述了Hibernate包的功能和正确的使用方法。
  
  阅读我的书Hibernate: A Developer's Notebook,也是一种快速上手的好方法。它直接但详细地讲述了如何在Java项目中设置Hibernate,以及如何使用它的一些最重要的功能。其中的代码示例普遍基于Hibernate和HSQLDB的早期版本,所以如果您想不加改动地使用它们,需要使用这两种软件的正确版本。无论如何,基本的概念是正确的,而且我希望能够尽快地针对Hibernate 3更新本书。
  
  另一本有趣的书是Better Faster Lighter Java,作者是Bruce Tate 和Justin Gehtland。书中给出了一些实用方法,可以以合理的方式完成实际的项目,这也是它流行的原因之一。它在如何评估和使用(或否决)可用的Java技术方面给出了合理建议,并作为正确方法的例子提到了Hibernate和Spring。
  
  最后,“Working with Hibernate in Eclipse”(它预先提到了更强大的新的alpha版的Hibernate 3工具)中详细讲述了如何将一个叫做Hibernate Synchronizer的Eclipse插件与Hibernate一起使用。
March 17

答案(仿佛更抽象)^_^

    class begin
    {   
        static void Main()
        {
            //初始化生日集合         
            生日集合 srjh=new 生日集合();
            srjh.Add(new 生日类(3,4));
            srjh.Add(new 生日类(3,5));
            srjh.Add(new 生日类(3,8));
            srjh.Add(new 生日类(6,4));
            srjh.Add(new 生日类(6,7));
            srjh.Add(new 生日类(9,1));
            srjh.Add(new 生日类(9,5));
            srjh.Add(new 生日类(12,1));
            srjh.Add(new 生日类(12,2));
            srjh.Add(new 生日类(12,8));
          
            //开始工作流
            工作流.BEG(srjh);           
            System.Console.Read();
        }   
    }
//工作流
    class 工作流
    {
        /**//*    开始结点
         *     ↓
         *    结点A:如果我不知道的话 →结点X:小明知道(该节点分支略)
         *     ↓
         *    结点B:小强肯定也不知道
         *     ↓
         *    结点C: 小强说:现在我知道了
         *     ↓
         *    结点D:小明说:哦,那我也知道了
         *     ↓
         *    结束结点
         *
         */
     
        public static void BEG(生日集合 obj)
        {
            if(obj !=null)
            {  
                A(obj);//下一结点
            }
        }
        //结点A:如果我不知道的话
        private static void A(生日集合 obj)
        {
            生日集合 jh=AI.小明分析(obj);
            if(jh.Count==0)
            {
                B(obj); //下一结点
            }
            else
            {
                //小明可以光凭月知道的集合
                //该节点分支略
            }
        }
        //结点B:小强肯定也不知道
        private static void B(生日集合 obj)
        {
            //得到小强光凭日期就能知道的集合
            生日集合 小强知道的集合=AI.小强分析(obj);
            //小明之所以知道小强肯定不知道,
            //是因为小明知道的月份不是小强光凭日期就能知道的
                    
            生日集合 排除的集合=new 生日集合();
            foreach(生日类 temp in 小强知道的集合)
            {
                foreach(生日类 tp in obj)
                {
                    if(temp.月==tp.月)
                    {
                        排除的集合.Add(tp);
                    }
                }
            }
            集合操作.排除(obj,排除的集合);
            C(obj);//下一结点
        }
   
        //结点C: 小强说:现在我知道了
        private static void C(生日集合 obj)
        {
            生日集合 小强知道的集合=AI.小强分析(obj);
            D(小强知道的集合); //下一结点
        }
        //结点D:小明说:哦,那我也知道了
        private static void D(生日集合 obj)
        {
            生日集合 小明知道的集合=AI.小明分析(obj);
            END(小明知道的集合);//下一结点
        }
        //完成结点:
        private static void END(生日集合 obj)
        {
            //完成,输出到屏幕
            foreach(生日类 temp in obj)
            {
                System.Console.WriteLine(temp.月.ToString() +"-" +temp.日.ToString());
            }
        }
    }
    //功能扶助类
    class 集合操作
    {
        public static void 排除(生日集合 s,生日集合 v)
        {
            foreach(生日类 temp in v)
            {
                s.Remove(temp);
            }
        }
    }
   
    class 生日类
    {
        public int 日=0;
        public int 月=0;
        public 生日类(int y,int r)
        {
            日=r;
            月=y;
        }
    }
   
    class 生日集合:System.Collections.ArrayList
    {
        public void 添加(生日类 v)
        {
            this.Add(v);
        }
        public void 移除(生日类 v)
        {
            this.Remove(v);
        }
    }
    class AI
    {
        public static 生日集合 小明分析(生日集合 v)
        {
            //AI,如果有维一的月份,则小明能确定
            //月份为1到12
            生日集合 jh=new 生日集合();
            int n=0;//记数器,如果n=1表示有
            for(int i=1;i<=12;i++)
            {
                生日类 x=null;
                foreach(生日类 temp in v)
                {
                    if(temp.月==i)
                    {
                        n=n+1;
                        x=temp;
                    }                  
                }
                    if(n==1)
                    {
                        jh.Add(x);
                    }
                n=0;
            }
            return jh;
        }
        public static 生日集合 小强分析(生日集合 v)
        {
            //AI,如果有维一的日,则小强能确定
            //日为1到31
            生日集合 jh=new 生日集合();
            int n=0;//记数器,如果n=1表示有
            for(int i=1;i<=31;i++)
            {
                生日类 x=null;
                foreach(生日类 temp in v)
                {
                    if(temp.日==i)
                    {
                        n=n+1;
                        x=temp;
                    }   
                }
                if(n==1)
                {
                    jh.Add(x);
                }
                n=0;
            }
            return jh;
        }
    }

张老师的生日??

小明和小紅都是张老师的学生,张老师的生日是M月N日,2人都知道张老师的生日是下列10组中的一天,张老师把M值告诉了小明,把N值告诉了小紅,张老师问他们知道他的生日是那一天吗?
3月4日 3月5日 3月8日 6月4日 6月7日
9月1日 9月5日 12月1日 12月2日 12月8日
小明说:如果我不知道的话,小紅肯定也不知道
小紅说:本來我也不知道,但是现在我知道了
小明说:哦,那我也知道了
请根据以上对话推断出张老师的生日是哪一天
 

文韬 雍

Occupation
感谢访问!
Please wait...
Sorry, the comment you entered is too long. Please shorten it.
You didn't enter anything. Please try again.
Sorry, we can't add your comment right now. Please try again later.
To add a comment, you need permission from your parent. Ask for permission
Your parent has turned off comments.
Sorry, we can't delete your comment right now. Please try again later.
You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
Complete the security check below to finish leaving your comment.
The characters you type in the security check must match the characters in the picture or audio.
wrote:
黄山的照片呢?
 
Apr. 30

QQ(用新窗口打开)

记得Q我哦!ps:用新窗口打开
No list items have been added yet.

Windows Media Player

No list items have been added yet.

Feed

The owner hasn't specified a feed for this module yet.