用户操作
[即时聊天] [发私信] [加为好友]
刘晓伟ID:lxwde
167458次访问,排名453好友0人,关注者2
lxwde的文章
原创 27 篇
翻译 34 篇
转载 0 篇
评论 244 篇
最近评论
mldstk:wow power leveling
lshvs2006:你好,你設計的東東非常不錯。
但是,現在有個疑問,不知道,怎樣保存設計的文件,
存成XML 文件格式可能會好一點,但是,不知道如何去存? 需要調用什么接口 或是 需要寫什么 方法嗎?

期待您的指教。謝謝

lsh2011@163.com
zeeler:补上这一部分吧(本人中文表述能力没有lxwde强哦 :) ):
The Singleton
也许最简单的设计模式是Singleton模式了,它可以给某种类型提供唯一的对象,下面是个例子:
(译者按:例子省略)
创建一个唯一对象的关键是防止客户程序员(client programmer)用其他任意方法创建对象,只能用你提供的方法。你必须把所有构造器写成p……
zeeler:翻译的不错呀,全力支持!
不过在Design principles和Classifying patterns之间还有个The Singleton部分好像lxwde漏掉了?还是Bruce Eckel修改版面了?
总之,支持呀,本来我也想翻译一下的,不过没有lxwde这么有毅力,翻译一节就停了,实在很累的,所以非常敬佩lxwde能坚持做这么多!
roger_77:可惜,
这个库被boost放弃了,加入另一个ASIO的网络类库
文章分类
收藏
    相册
    链接
    My articles on codeproject
    SharpFormEditor下载
    Thinking in Patterns中文版
    友情链接
    alai04
    C++的罗浮宫
    fatalerror99
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    翻译 翻译TIPatterns--多个编程语言(Multiple languages)-2收藏

    新一篇: 但凡你能够 | 旧一篇: 翻译TIPatterns--多个编程语言(Multiple languages)-1

    多个编程语言Multiple languages-2

    。。。。。。

    创造一门语言    
        
        使用Jython,在你的程序内部创造一种解释(interpreted)语言是极其简单的。考虑 《Thinking in Java》第二版第八章greenhouse控制器的那个例子。那种情形下你会希望最终用户——也就是管理greenhouse的那个人——能够通过配置来控制整个系统,于是一个简单的脚本语言就成了理想的解决方案。
        要创建这个语言,我们只需简单的写一组Python类,每个类的构造函数会把它自己添加到一个(静态的)master链表。公共的数据和行为会被factor到叫作Event的基类。每个Event对象都会包括一个action字符串(for simplicity——实际应用中,你应该安排一些functionality)和运行该事件(event)的设定时间。构造函数初始化这些成员变量,然后把新创建的Event对象添加到一个叫作events(在类的内部定义,但是位于所有方法的外部,所以它是静态的)的静态链表.

    #:interpreter:GreenHouseLanguage.py
     
    class Event:
      events = [] # static
      def __init__(self, action, time):
        self.action = action
        self.time = time
        Event.events.append(self)
      # Used by sort(). This will cause
      # comparisons to be based only on time:
      def __cmp__ (self, other):
        if self.time < other.time: return -1
        if self.time > other.time: return 1
        return 0
      def run(self):
        print "%.2f: %s" % (self.time, self.action)
     
    class LightOn(Event):
      def __init__(self, time):
        Event.__init__(self, "Light on", time)
     
    class LightOff(Event):
      def __init__(self, time):
        Event.__init__(self, "Light off", time)
     
    class WaterOn(Event):
      def __init__(self, time):
        Event.__init__(self, "Water on", time)
     
    class WaterOff(Event):
      def __init__(self, time):
        Event.__init__(self, "Water off", time)
     
    class ThermostatNight(Event):
      def __init__(self, time):
        Event.__init__(self,"Thermostat night", time)
     
    class ThermostatDay(Event):
      def __init__(self, time):
        Event.__init__(self, "Thermostat day", time)
     
    class Bell(Event):
      def __init__(self, time):
        Event.__init__(self, "Ring bell", time)
     
    def run():
      Event.events.sort();
      for e in Event.events:
        e.run()
     
    # To test, this will be run when you say:
    # python GreenHouseLanguage.py
    if __name__ == "__main__":
      ThermostatNight(5.00)
      LightOff(2.00)
      WaterOn(3.30)
      WaterOff(4.45)
      LightOn(1.00)
      ThermostatDay(6.00)
      Bell(7.00)
      run()
    ##~


        每个派生类的构造函数都要调用基类的构造函数,基类的构造函数把新建的对象加入到链表。run()函数给整个链表排序,它自动的使用Event类所定义的__cmp__()方法只根据时间来进行比较。上面的例子,只是打印链表的内容,但是在实际系统中,它会等待每个事件设定的时间,然后运行那个事件。
        __main__函数这部分对这些类做了一下简单的测试。
        上面的文件现在已经是一个模块了,它可以被包括进(included)另外一个Python程序,用以定义那个程序所包含的所有类。但是,我们不用普通的Python程序,我们使用Java的Jython。这其实是非常简单的:你只需引入一些Jython类,创建一个PythonInterpreter对象,然后cause the Python files to be loaded:


    //- interpreter:GreenHouseController.java
    package interpreter;
    import org.python.util.PythonInterpreter;
    import org.python.core.*;
    import junit.framework.*;
     
    public class
    GreenHouseController extends TestCase  {
      PythonInterpreter interp =
        new PythonInterpreter();
      public void test() throws PyException  {
        System.out.println(
          "Loading GreenHouse Language");
        interp.execfile("GreenHouseLanguage.py");
        System.out.println(
          "Loading GreenHouse Script");
        interp.execfile("Schedule.ghs");
        System.out.println(
          "Executing GreenHouse Script");
        interp.exec("run()");
      }
      public static void
      main(String[] args) throws PyException  {
        junit.textui.TestRunner.run(GreenHouseController.class);
      }
    } ///:~


        PythonInterpreter对象是一个完整的Python解释器,它可以从Java程序接受命令。其中一个命令是execfile(),这个命令告诉解释器去执行它所找到的特定文件所包含的所有语句。通过执行GreenHouseLanguage.py,那个文件里所有的类都会被加载到PythonInterpreter对象,于是解释器就“拥有了” greehouse控制器语言。Schedule.ghs是由最终用户创建的用来控制greenhouse的文件。下面是一个例子:

    //:! interpreter:Schedule.ghs
    Bell(7.00)
    ThermostatDay(6.00)
    WaterOn(3.30)
    LightOn(1.00)
    ThermostatNight(5.00)
    LightOff(2.00)
    WaterOff(4.45)
    ///:~
     
        这就是interpreter设计模式所要达到的目的:使你的程序的配置对于最终用户来说尽可能的简单。使用Jython你几乎可以毫不费力的达到这个效果。
        PythonInterpreter还有一个可供使用的方法是exec(),通过它你可以向解释器发送命令。上例中,run()函数就是通过exec().被调用的。
     记住,要运行这个程序,你必须到
    http://jython.sourceforge.net下载并运行Jython(实际上,你只需要把jython.jar放到你的CLASSPATH就可以了)。上面这些做好以后,它就可以像其它Java程序那样运行了。

     

    控制解释器Controlling the interpreter
        
        前面的例子只是创建解释器并且让它运行外部脚本。本章的剩余部分,我们会讲述更为复杂的与Python交互的方法。要在Java范围内对PythonInterpreter施加更多的控制,最简单的方法就是,发送数据给解释器,然后再从它取回数据(pull data back out)。


    提交数据Putting data in
        为了向你的Python程序插入数据,PythonInterpreter类有一个看似简单的方法:set( ).。实际上,set( )可以接受不同类型的数据并且对它们进行转换。下面的例子是一个关于set( )不同用法的相当全面的练习,一道给出的那些注释提供了相当完整的解释。

    //- interpreter:PythonInterpreterSetting.java
    // Passing data from Java to python when using
    // the PythonInterpreter object.
    package interpreter;
    import org.python.util.PythonInterpreter;
    import org.python.core.*;
    import java.util.*;
    import com.bruceeckel.python.*;
    import junit.framework.*;
     
    public class
    PythonInterpreterSetting extends TestCase  {
      PythonInterpreter interp =
        new PythonInterpreter();
      public void test() throws PyException  {
        // It automatically converts Strings
        // into native Python strings:
        interp.set("a", "This is a test");
        interp.exec("print a");
        interp.exec("print a[5:]"); // A slice
        // It also knows what to do with arrays:
        String[] s = { "How", "Do", "You", "Do?" };
        interp.set("b", s);
        interp.exec("for x in b: print x[0], x");
        // set() only takes Objects, so it can't
        // figure out primitives. Instead,
        // you have to use wrappers:
        interp.set("c", new PyInteger(1));
        interp.set("d", new PyFloat(2.2));
        interp.exec("print c + d");
        // You can also use Java's object wrappers:
        interp.set("c", new Integer(9));
        interp.set("d", new Float(3.14));
        interp.exec("print c + d");
        // Define a Python function to print arrays:
        interp.exec(
          "def prt(x): \n" +
          "  print x \n" +
          "  for i in x: \n" +
          "    print i, \n" +
          "  print x.__class__\n");
        // Arrays are Objects, so it has no trouble
        // figuring out the types contained in arrays:
        Object[] types = {
          new boolean[]{ true, false, false, true },
          new char[]{ 'a', 'b', 'c', 'd' },
          new byte[]{ 1, 2, 3, 4 },
          new int[]{ 10, 20, 30, 40 },
          new long[]{ 100, 200, 300, 400 },
          new float[]{ 1.1f, 2.2f, 3.3f, 4.4f },
          new double[]{ 1.1, 2.2, 3.3, 4.4 },
        };
        for(int i = 0; i < types.length; i++) {
          interp.set("e", types[i]);
          interp.exec("prt(e)");
        }
        // It uses toString() to print Java objects:
        interp.set("f", new Date());
        interp.exec("print f");
        // You can pass it a List
        // and index into it...
        List x = new ArrayList();
        for(int i = 0; i < 10; i++)
            x.add(new Integer(i * 10));
        interp.set("g", x);
        interp.exec("print g");
        interp.exec("print g[1]");
        // ... But it's not quite smart enough
        // to treat it as a Python array:
        interp.exec("print g.__class__");
        // interp.exec("print g[5:]); // Fails
        // If you want it to be a python array, you
        // must extract the Java array:
        System.out.println("ArrayList to array:");
        interp.set("h", x.toArray());
        interp.exec("print h.__class__");
        interp.exec("print h[5:]");
        // Passing in a Map:
        Map m = new HashMap();
        m.put(new Integer(1), new Character('a'));
        m.put(new Integer(3), new Character('b'));
        m.put(new Integer(5), new Character('c'));
        m.put(new Integer(7), new Character('d'));
        m.put(new Integer(11), new Character('e'));
        System.out.println("m: " + m);
        interp.set("m", m);
        interp.exec("print m, m.__class__, " +
          "m[1], m[1].__class__");
        // Not a Python dictionary, so this fails:
        //! interp.exec("for x in m.keys():" +
        //!   "print x, m[x]");
        // To convert a Map to a Python dictionary,
        // use com.bruceeckel.python.PyUtil:
        interp.set("m", PyUtil.toPyDictionary(m));
        interp.exec("print m, m.__class__, " +
          "m[1], m[1].__class__");
        interp.exec("for x in m.keys():print x,m[x]");
      }
      public static void
      main(String[] args) throws PyException  {
        junit.textui.TestRunner.run(
          PythonInterpreterSetting.class);
      }
    } ///:~

        对于Java来说,大多数时候真正的对象(real objects)和基本类型(primitive types)之间的差别总会带来麻烦。一般而言,如果你传递给set( ),方法的是一个通常的对象(regular object),它是知道如何处理的,但是如果你想传入一个基本类型(primitive type)的对象,就必须得作转换。一种做法是创建一个“Py”类型,比如PyInteger和PyFloat,但实际上你也可以使用Java自带的对象外覆类比如Integer和Float,这些可能更容易记住。
        上面程序的前一部分你会看到有一个exec( )含有以下的Python语句:
        pint a[5:]
        索引语句里的那个分号表明这是一个Python切片(slice),所谓切片就是从一个原始数组里产生出某一范围内的元素。在这里,它产生出一个包含从第5号元素开始直到原来数组最后一个元素的新数组。你也可以用“a[3:5]”产生第3号到第5号元素,或者用“a[:5]”产生第0号到第5号元素。在这个语句里使用切片的原因是为了保证Java的String确实被转换成了一个Python字符串,而Python字符串是可以被当作一个字符数组来对待的。
        你会看到我们是能够用exec( ),来创建一个Python函数的(虽然有点别扭)。prt( )函数打印整个数组,然后(to make sure it’s a real Python array)遍历数组的每一个元素并且把它打印出来。最后,它打印数组的类名称,我们可以据此看看发生是什么转换(Python不仅有运行时刻信息,它还有与Java的反射相当的东西)。prt( )函数用以打印来自Java的基本类型的数组。
        尽管可以使用set( )把一个Java的ArrayList传入解释器,而且你也能把它当作数组那样进行索引,但是试图从它产生一个切片是不会成功的。为了把它完全转换成一个数组,一种方法是简单的利用toArray( )从中取出一个Java数组,然后再把它传给解释器。set( )方法会把它转换成一个PyArray ——Jython提供的一个类——它可以被当作一个Python数组来处理(你也可以显式的创建一个PyArray,但是似乎没有这个必要)。
        最后,我们创建了一个Map并且把它直接传给了解释器。虽然可以对While it is possible to do simple things like index into the resulting object,但它并不是一个真正的Python字典(dictionary),所以你不能调用像keys( )那样的方法。并没有直接了当的方法可以把一个Java的Map转换成一个Python字典,于是我就写了一个叫做toPyDictionary( )的小程序并且把它作为com.bruceeckel.python.PyUtil的一个静态方法。它还包括一些从Python数组提取数据到Java List和从Python字典提取数据到Java Map的一些小程序。

    //- com:bruceeckel:python:PyUtil.java
    // PythonInterpreter utilities
    package com.bruceeckel.python;
    import org.python.util.PythonInterpreter;
    import org.python.core.*;
    import java.util.*;
     
    public class PyUtil {
      /** Extract a Python tuple or array into a Java
      List (which can be converted into other kinds
      of lists and sets inside Java).
      @param interp The Python interpreter object
      @param pyName The id of the python list object
      */
      public static List
      toList(PythonInterpreter interp, String pyName){
        return new ArrayList(Arrays.asList(
          (Object[])interp.get(
            pyName, Object[].class)));
      }
      /** Extract a Python dictionary into a Java Map
      @param interp The Python interpreter object
      @param pyName The id of the python dictionary
      */
      public static Map
      toMap(PythonInterpreter interp, String pyName){
        PyList pa = ((PyDictionary)interp.get(
          pyName)).items();
        Map map = new HashMap();
        while(pa.__len__() != 0) {
          PyTuple po = (PyTuple)pa.pop();
          Object first = po.__finditem__(0)
            .__tojava__(Object.class);
          Object second = po.__finditem__(1)
            .__tojava__(Object.class);
          map.put(first, second);
        }
        return map;
      }
      /** Turn a Java Map into a PyDictionary,
      suitable for placing into a PythonInterpreter
      @param map The Java Map object
      */
      public static PyDictionary
      toPyDictionary(Map map) {
        Map m = new HashMap();
        Iterator it = map.entrySet().iterator();
        while(it.hasNext()) {
          Map.Entry e = (Map.Entry)it.next();
          m.put(Py.java2py(e.getKey()),
            Py.java2py(e.getValue()));
        }
        // PyDictionary constructor wants a Hashtable:
        return new PyDictionary(new Hashtable(m));
      }
    } ///:~


    下面是(黑盒)单元测试的代码:


    //- com:bruceeckel:python:Test.java
    package com.bruceeckel.python;
    import org.python.util.PythonInterpreter;
    import java.util.*;
    import junit.framework.*;
     
    public class Test extends TestCase  {
      PythonInterpreter pi =
        new PythonInterpreter();
      public void test1() {
        pi.exec("tup=('fee','fi','fo','fum','fi')");
        List lst = PyUtil.toList(pi, "tup");
        System.out.println(lst);
        System.out.println(new HashSet(lst));
      }
      public void test2() {
        pi.exec("ints=[1,3,5,7,9,11,13,17,19]");
        List lst = PyUtil.toList(pi, "ints");
        System.out.println(lst);
      }
      public void test3() {
        pi.exec("dict = { 1 : 'a', 3 : 'b', " +
          "5 : 'c', 9 : 'd', 11 : 'e'}");
        Map mp = PyUtil.toMap(pi, "dict");
        System.out.println(mp);
      }
      public void test4() {
        Map m = new HashMap();
        m.put("twas", new Integer(11));
        m.put("brillig", new Integer(27));
        m.put("and", new Integer(47));
        m.put("the", new Integer(42));
        m.put("slithy", new Integer(33));
        m.put("toves", new Integer(55));
        System.out.println(m);
        pi.set("m", PyUtil.toPyDictionary(m));
        pi.exec("print m");
        pi.exec("print m['slithy']");
      }
      public static void main(String args[]) {
        junit.textui.TestRunner.run(Test.class);
      }
    } ///:~


    下一小节我们会讲述(数据)提取工具的用法。


    取出数据Getting data out
        存在很多种不同的方法从PythonInterpreter提取数据。如果你只是调用get( )方法,把对象标识符作为一个字符串传给它,它会返回一个PyObject(由org.python.core所提供的支持类的一部分)。可以用__tojava__( )方法对它进行“cast”,但是还有比这更好的方法:

    1. Py类有一些很方便的方法,比如py2int( ),可以接受一个PyObjec并且把它转换成若干不同的类型。
    2. get( )有一个重载过的版本可以接受预期的Java Class对象作为第二个参数,并且产生出一个具有其运行时刻类型(run-time type)的对象(所以说在你的Java代码里你仍然需要对得到的结果进行一次cast)。

          使用第二种方法,从PythonInterpreter取出一个数组是非常简单的。这一点显得尤为有用,因为Python对字符串和文件处理都异常的出色,所以通常你会希望把结果作为一个字符串数组提出出来。例如,你可以使用Python的glob( )函数对文件名进行通配符扩展(wildcard expansion),就像接下来的例子所展示的那样:

    //- interpreter:PythonInterpreterGetting.java
    // Getting data from the PythonInterpreter object.
    package interpreter;
    import org.python.util.PythonInterpreter;
    import org.python.core.*;
    import java.util.*;
    import com.bruceeckel.python.*;
    import junit.framework.*;
     
    public class
    PythonInterpreterGetting extends TestCase {
      PythonInterpreter interp =
        new PythonInterpreter();
      public void test() throws PyException  {
        interp.exec("a = 100");
        // If you just use the ordinary get(),
        // it returns a PyObject:
        PyObject a = interp.get("a");
        // There's not much you can do with a generic
        // PyObject, but you can print it out:
        System.out.println("a = " + a);
        // If you know the type it's supposed to be,
        // you can "cast" it using __tojava__() to
        // that Java type and manipulate it in Java.
        // To use 'a' as an int, you must use
        // the Integer wrapper class:
        int ai= ((Integer)a.__tojava__(Integer.class))
          .intValue();
        // There are also convenience functions:
        ai = Py.py2int(a);
        System.out.println("ai + 47 = " + (ai + 47));
        // You can convert it to different types:
        float af = Py.py2float(a);
        System.out.println("af + 47 = " + (af + 47));
        // If you try to cast it to an inappropriate
        // type you'll get a runtime exception:
        //! String as = (String)a.__tojava__(
        //!   String.class);
       
        // If you know the type, a more useful method
        // is the overloaded get() that takes the
        // desired class as the 2nd argument:
        interp.exec("x = 1 + 2");
        int x = ((Integer)interp
          .get("x", Integer.class)).intValue();
        System.out.println("x = " + x);
       
        // Since Python is so good at manipulating
        // strings and files, you will often need to
        // extract an array of Strings. Here, a file
        // is read as a Python array:
        interp.exec("lines = " +
          "open('PythonInterpreterGetting.java')" +
          ".readlines()");
        // Pull it in as a Java array of String:
        String[] lines = (String[])
          interp.get("lines", String[].class);
        for(int i = 0; i < 10; i++)
          System.out.print(lines[i]);
       
        // As an example of useful string tools,
        // global expansion of ambiguous file names
        // using glob is very useful, but it's not
        // part of the standard Jython package, so
        // you'll have to make sure that your
        // Python path is set to include these, or
        // that you deliver the necessary Python
        // files with your application.
        interp.exec("from glob import glob");
        interp.exec("files = glob('*.java')");
        String[] files = (String[])
          interp.get("files", String[].class);
        for(int i = 0; i < files.length; i++)
          System.out.println(files[i]);
       
        // You can extract tuples and arrays into
        // Java Lists with com.bruceeckel.PyUtil:
        interp.exec(
          "tup = ('fee', 'fi', 'fo', 'fum', 'fi')");
        List tup = PyUtil.toList(interp, "tup");
        System.out.println(tup);
        // It really is a list of String objects:
        System.out.println(tup.get(0).getClass());
        // You can easily convert it to a Set:
        Set tups = new HashSet(tup);
        System.out.println(tups);
        interp.exec("ints=[1,3,5,7,9,11,13,17,19]");
        List ints = PyUtil.toList(interp, "ints");
        System.out.println(ints);
        // It really is a List of Integer objects:
        System.out.println((ints.get(1)).getClass());
       
        // If you have a Python dictionary, it can
        // be extracted into a Java Map, again with
        // com.bruceeckel.PyUtil:
        interp.exec("dict = { 1 : 'a', 3 : 'b'," +
          "5 : 'c', 9 : 'd', 11 : 'e' }");
        Map map = PyUtil.toMap(interp, "dict");
        System.out.println("map: " + map);
        // It really is Java objects, not PyObjects:
        Iterator it = map.entrySet().iterator();
        Map.Entry e = (Map.Entry)it.next();
        System.out.println(e.getKey().getClass());
        System.out.println(e.getValue().getClass());
      }
      public static void
      main(String[] args) throws PyException  {
        junit.textui.TestRunner.run(
          PythonInterpreterGetting.class);
      }
    } ///:~


        最后两个例子展示了从Python的垫片(tuples)和链表(lists)中提取数据到Java Lists,以及从Python 字典中提取数据到Java Maps。上述两种情况都需要用到比标准Jython库所提供的更多的处理方法,所以我又写了一些小程序放在com.bruceeckel.pyton里。PyUtil: toList( )是用来从一个Python序列产生一个List,toMap( )用来从Python字典产生出一个Map。PyUtil所提供的方法使得在Java和Python之间来回传递重要的数据结构变得更为简单。


    多个解释器Multiple interpreters
        很有必要再提一下,你可以在一个程序里声明多个PythonInterpreter对象,每个对象有它自己的名字空间:

    //- interpreter:MultipleJythons.java
    // You can run multiple interpreters, each
    // with its own name space.
    package interpreter;
    import org.python.util.PythonInterpreter;
    import org.python.core.*;
    import junit.framework.*;
     
    public class MultipleJythons extends TestCase  {
      PythonInterpreter
        interp1 =  new PythonInterpreter(),
        interp2 =  new PythonInterpreter();
      public void test() throws PyException {
        interp1.set("a", new PyInteger(42));
        interp2.set("a", new PyInteger(47));
        interp1.exec("print a");
        interp2.exec("print a");
        PyObject x1 = interp1.get("a");
        PyObject x2 = interp2.get("a");
        System.out.println("a from interp1: " + x1);
        System.out.println("a from interp2: " + x2);
      }
      public static void
      main(String[] args) throws PyException  {
        junit.textui.TestRunner.run(MultipleJythons.class);
      }
    } ///:~


        当运行程序的时候你会看到,每个PythonInterpreter所包含的a的值是不同的。

    。。。。。。


                            目录

    发表于 @ 2005年02月21日 15:16:00|评论(loading...)|编辑

    新一篇: 但凡你能够 | 旧一篇: 翻译TIPatterns--多个编程语言(Multiple languages)-1

    评论

    #chair 发表于2005-06-01 10:17:00  IP: 61.186.252.*
    good
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © lxwde