Chris さんのプロフィール卓尔的文フォトブログリストその他 ツール ヘルプ

ブログ


6月15日

最近变成了旅游

   来到了一个叫Farsund的城市,据说夏天开船来挪威的人必定先经过这里。。。这里很漂亮。。特别是山。。太JB壮观了。。还有海。。很宽旷。。城市估计是老城市了。。很多地方都很破很旧。。每天陪个小朋友一起玩。。他当导游。。我汗。。。这个小孩很帅气。。。有点调皮。。。。。决定明天带照相机出去。。。然后上传。。看看不一样的挪威。
                     最郁闷的是闲的慌。。。。哎。。吃的还不错。。。后悔的是。。怎么来这没多带点衣服。。。。冷的要死。。
    好了。。。晚上学习学习。。。。睡觉醒来又是吃。。。。好累啊。。。
6月9日

关于数据库接口JDBC和监听接口的思考

这两个东西似乎是用的最多的。。可是今天才发觉是那么的不一样。。。。要怪就怪在都是一个名字接口上。。。其实本质区别很大。。。不知道自己理解的对不对。。
先说监听接口, 都知道要用一个接口就要先把接口当成自己的成员。这样来说。。。有两个类, A, B 一个接口 C。 而在实际中用监听器,假定B是要用监听器接口C, 那么在这里我们要用Implement C, 然后在类里面就写方法就行了,当有键被按下就会处理对应的动作。 而对于A来说,我们可以把他也看成一个对象,键盘监听。当有键盘动作时,就会运行C接口的一个方法,前提是C是A的成员, 但是C是接口,没有实例,所以其实在这里是 C c=new B(); 然后用c去调用。可是这里好了。。他怎么知道是B实现了他呢。。那好。这里肯定有个工厂,用工厂来创建于实现了C方法的对象。更深入工厂怎么知道时候B实现了他,而又创建B的呢。。。这里就可能是反射机制了,然后有JAVA  实现接口的内部机制, 当某个类实现了某个接口,这个接口的工厂就把这个类名加个.CLASS放在了工厂里面然后就可以自由的选择和产生对象了。。。。其实这也是我的猜测。。。
 
而对于JDBC 这里的接口,最大的不同就时候在这里面,用户能用到的角色和监听接口用的角色是相反的。如, A,B 类, C 接口。B 实现了C。 实际上我们在程序中是在程序A 里面用到C, 换句话说是C为A的成员, 而C就是JDBC,所谓的接口。那么B在哪里呢,对了B在数据库中,他实现了C,有C的方法,并且在方法里面写好了对应的怎么去处理数据。这样就达到了程序和数据库的分离,提高了系统性能。 当我们要在 某个程序里用到数据库工作时, 首先要加载这个数据库的驱动,简单来说就是JDBC的接口,就要先加载Class.forName(DBDRIVER) ;  生成这个驱动对象,在这里有一点我不明白,搜索到的答案:
使用JDBC时,我们都会很自然得使用下列语句:
1Class.forName("com.mysql.jdbc.Driver");
2String url = "jdbc:mysql://127.0.0.1/test?useUnicode=true&characterEncoding=utf-8";
3String user = "";
4String psw = "";
5Connection con = DriverManager.getConnection(url,user,psw);
    为什么说很自然呢,因为无论是网上还是书本教程上得例子都是这样的,而且程序也确实正常运行了,于是大家也就心安理得的找葫芦画瓢下去了。 
    一定要有这一句吗?不是的,我们完全可以用这样一句代替它:
1com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver();
2//or:
3//new com.mysql.jdbc.Driver();    
4String url = "jdbc:mysql://127.0.0.1/test?useUnicode=true&characterEncoding=utf-8";
5String user = "";
6String psw = "";
7Connection con = DriverManager.getConnection(url,user,psw);
    大家可能都看出个大概来了,我们只需要在调用DriverManager的getConnection方法之前,保证相应的Driver类已经被加载到 jvm中,并且完成了类的初始化工作就行了,而具体是怎样实现这个功能却是没有讲究的。上面两种方法都可以实现这个功能,因此程序可以正常运行。注意了,如果我们进行如下操作,程序是不能正常运行的,因为这样仅仅使Driver类被装载到jvm中,却没有进行相应的初始化工作。
1com.mysql.jdbc.Driver driver = null;
2//or:    
3ClassLoader cl = new ClassLoader();
4cl.loadClass("com.mysql.jdbc.Driver");
    我们都知道JDBC是使用Bridge模式进行设计的,DriverManager就是其中的Abstraction,java.sql.Driver是 Implementor,com.mysql.jdbc.Driver是Implementor的一个具体实现(请参考GOF的Bridge模式的描述)。大家注意了,前一个Driver是一个接口,后者却是一个类,它实现了前面的Driver接口。 
    Bridge模式中,Abstraction(DriverManager)是要拥有一个Implementor(Driver)的引用的,但是我们在使用过程中,并没有将Driver对象注册到DriverManager中去啊,这是怎么回事呢?jdk文档对Driver的描述中有这么一句:
When a Driver class is loaded, it should create an instance of itself and register it with the DriverManager
哦,原来是com.mysql.jdbc.Driver在装载完后自动帮我们完成了这一步骤。源代码是这样的:
package com.mysql.jdbc

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
 
// ~ Static fields/initializers
 
// --------------------------------------------- //
 
// Register ourselves with the DriverManager
 
//    
 static {
    try
{
              java.sql.DriverManager.registerDriver(
new Driver());
          }
 catch (SQLException E) {
              
throw new RuntimeException("Can't register driver!");
          }

  }

// ~ Constructors
 
// -----------------------------------------------------------    
/** *//**//**
  * Construct a new driver and register it with DriverManager
  *
  * 
@throws SQLException
  *             if a database error occurs.
  
*/

 
public Driver() throws SQLException {
     
// Required for Class.forName().newInstance()    
 }

}
Class.forName(xxx.xx.xx) 返回的是一个类, .newInstance() 后才创建一个对象 Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段
在JDBC驱动中,有一块静态代码,也叫静态初始化块,它执行的时间是当class调入到内存中就执行(你可以想像成,当类调用到内存后就执行一个方法)。所以很多人把jdbc driver调入到内存中,再实例化对象是没有意义的。
 
然后此时就可以调用DriverManager.getConnection(DBURL,DBUSER,DBPASSWORD) ;去连接数据库,成功连接以后,就可以得到一个控制器,负责递交SQL语句给数据库去执行,stmt = conn.createStatement() ;
  stmt.executeUpdate(sql) ;  由于数据库是用于网络的,所以这里的接口概念要变一下,客户端传送SQL语句过去, 数据库端得到,然后通过一个对外接口来接受然后处理。
重要的概念是,接口是负责把 一类的事物,或者要被选择的事物集中起来,可以利用一个接口的声明来动态的调用。
 

【转载】 写的不错

 
大多数人认为,接口的意义在于顶替多重继承。众所周知Java没有c++那样多重继承的机制,但是却能够实作多个接口。其实这样做是很牵强的,接口和继承是完全不同的东西,接口没有能力代替多重继承,也没有这个义务。接口的作用,一言以蔽之,就是标志类的类别(type of class)。把不同类型的类归于不同的接口,可以更好的管理他们。OO的精髓,我以为,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如c++、java、c#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。(cowboy的名言是 “抽象就是抽去像的部分”,看似调侃,实乃至理)。

    设计模式中最基础的是工厂模式(Factory),在我最近的一个很简单的应用中,我想尽量的让我的程序能够在多个数据库间移植,当然,这涉及很多问题,单是如何兼容不同DBMS的SQL就让人头痛。我们不妨先把问题简单化,只考虑如何连接不同的数据库。

    假设我有很多个类,分别是Mysql.java、SQLServer.java、Oracle.java、DB2.java,他们分别连接不同的数据库,统一返回一个Connection对象,并且都有一个close方法,用于关闭连接。只需要针对你的DBMS,选择不同的类,就可以用了,但是我的用户他会使用什么数据库?我不知道,我希望的是尽量少的修改代码,就能满足他的需要。我可以抽象如下接口:

    package org.bromon.test;
    public interface DB
    {
    java.sql.Connection openDB(String url,String user,String password);
    void close();
    }

    这个接口只定义两个方法,没有任何有实际意义的代码,具体的代码由实作这个接口的类来给出,比如Mysql.java:

    Package org.bromon.test;
    import java.sql.*;
    public class Mysql implements DB
    {
    private String url=”jdbc:mysql:localhost:3306/test”;
    private String user=”root”;
    private String password=””;
    private Connection conn;
    public Connection openDB(url,user,password)

    {
    //连接数据库的代码
    }
    public void close()

    {
    //关闭数据库
    }
    }
    类似的当然还有Oracle.java等等,接口DB给这些类归了个类,在应用程序中我们这样定义对象:

    org.bromon.test.DB myDB;
    使用myDB来操作数据库,就可以不用管实际上我所使用的是哪个类,这就是所谓的“开-闭”原则。但是问题在于接口是不能实例化的,myDB=new DB(),这样的代码是绝对错误的,我们只能myDB=new Mysql()或者myDB=new Oracle()。麻烦了,我还是需要指定具体实例化的是哪个类,用了接口跟没用一样。所以我们需要一个工厂:

    package org.bromon.test;
    public class DBFactory
    {
    public static DB Connection getConn()

    {
    Return(new Mysql());
    }
    }

    所以实例化的代码变成:myDB=DBFactory.getConn();

    这就是23种模式中最基础的普通工厂(Factory),工厂类负责具体实例化哪个类,而其他的程序逻辑都是针对DB这个接口进行操作,这就是“针对接口编程”。责任都被推卸给工厂类了,当然你也可以继续定义工厂接口,继续把责任上抛,这就演变成抽象工厂(Abstract Factory)。

    整个过程中接口不负责任何具体操作,其他的程序要连接数据库的话,只需要构造一个DB对象就OK,而不管工厂类如何变化。这就是接口的意义----抽象。

    继承的概念不用多说,很好理解。为什么要继承呢?因为你想重用代码?这绝对不是理由,继承的意义也在于抽象,而不是代码重用。如果对象A有一个run() 方法,对象B也想有这个方法,所以有人就Class B extends A。这是不经大脑的做法。如果在B中实例化一个A,调用A的Run()方法,是不是可以达到同样的目的?如下:

    Class B
    {
    A a=new A();
    a.run();
    }
    这就是利用类的聚合来重用代码,是委派模式的雏形,是GoF一贯倡导的做法。

    那么继承的意义何在?其实这是历史原因造成的,最开始的OO语言只有继承,没有接口,所以只能以继承来实现抽象,请一定注意,继承的本意在于抽象,而非代码重用(虽然继承也有这个作用),这是很多Java烂书最严重的错误之一,它们所造成的阴影,我至今还没有完全摆脱,坏书害人啊,尤其是入门类的,流毒太大。什么时候应该使用继承?只在抽象类中使用,其他情况下尽量不使用。抽象类也是不能实例化的,它仅仅提供一个模版而已,这就很能说明问题。

    软件开发的万恶之源,一是重复代码而不是重用代码,二是烂用继承,尤以c++程序员为甚。Java中取缔多重继承,目的就是制止烂用继承,实是非常明智的做法,不过很多人都不理解。Java能够更好的体现设计,这是让我入迷的原因之一。
6月8日

窗外

    挪威现在已经分不清了白天黑夜。。。。也分不清现在几点。。。。。什么都不知道。。。
                  现在临晨3点35.。。下面零散的有人在聊天。。。天亮的很大。。。刚准备睡觉。。感觉 。。似乎不是睡觉的天气。。
           下午和LM在海边散步。。。享受着挪威的阳光。。。看着海上一首首游艇在玩耍。。。发现这才是享受生活。。
                             下午碰到一个德国的同学。。。两个人打个赤脚。。。准备去海边游泳。。。哎-- --。要是穿着泳裤就好了。。他真爽。。在stavange已经找到工作了。。。我们要加油了。。。。威兄不错。。。。榜样。。。。。。为了年薪50W kr而奋斗。。。。
6月3日

我要变NB!

我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
我要变NB
好好学习。。天天看TCP/IP。。。。明天最后一门就放假拉!!!哈哈!!