25、设计模式之结构模式

结构型模式:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

 

2.1、Adapter(适配器模式):

 class C继承class A ,以达到A的代码重复利用;就是将class  A 的方法适配到 接口B中去,这种设计模式也是比较常用的;

上面是C继承了A,默认得到了2个方法,这种称为类适配模式,

若C没有继承A而是在C中声明了A为属性变量a,那么在实例C时,interfaceB c=new C();c.a.method2();也实现了和上面一样的功能,这种称为对象适配模式;

因为接口的每个方法,子类都要覆写,这样就造成子类不需要的方法也要去覆写;最好就是在实现类和接口之间增加一个抽象类,这样实现类就可以自由选择自己需要覆写那些方法了,增加灵活性。

比如:

AbstractB  implements  interfaceB{A a;method1(){a.method1();};method2(){a.method2();};method3();method4()}
//采用对象适配模式,加载资源类A的方法;也可采用类适配模式直接继承A加载
class C extends  AbstractB{method3()}
class D extends  AbstractB{method4()}

interfaceB d=new D();
d.method1();
d.method4();
 
 这种称为接口适配模式;个人理解叫"抽象类适配模式"为实现类提供了可以选择性地实现抽象方法,增加编写程序的灵活性;   2.2、Decorator(装配器模式) 适配模式是将资源类的方法 加载到接口中去,以供实现类调用; 而装配类可以理解为:选择使用简装版的A和精装版的C(把A装饰了一下)

 这样c.method()就在a.method的基础上增加了其他功能,采用对象适配模式加载方法;为什么不用C直接继承A,然后覆写method?那样的话没有体现复用代码的思想,也没体现装饰的含义,因为覆写就相当于重写做了个功能,装饰是在原功能之上添加点次要功能(比如一个毛坯房需要装饰,不是把拆了 重新建个别墅的意思);    2.3、Proxy(代理模式) 看过前面的类加载器,就知道父类加载器可以代理子类加载器去加载一个.class文件,直至祖先类成功加载为止;在现实生活中,一般你的父母可以代理你完成某些事项,又如你委托律师代理去打官司,又如你委托朋友代理缴纳社保(要提供两人的身份证),又如你要建房子,建筑公司代理你帮你拿到建房许可、房梁室内外设计、分包施工队、分包水电气装修、代办房产证等等。
 从结构上与装配模式相似,只是装配模式一般是没有划分模块功能;而代理模式是有分模块功能的,可以调用模块,利于代码的升级、维护;   2.4、Facade(外观模式)
ABCD互相没有依赖关系,实现解耦的目的;如果没有F封装这些方法,而是ABCD互持其它对象,比如B的方法发生了改变,ACD并不知道而继续加载使用,可能会出现程序错误;外观模式只需要通知F:B的某个方法改变了,F采取相应调整就可以了,而原来ACD都需要进行调整;   2.5、Bridge(桥接模式) 使用过数据库就会知道有个叫桥连接的概念:
Connection con=null;
Class.forName("com.mysql.jdbc.Driver");
con=DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis", "root", "111122");
//dosomgthing
con.close();
Connection、Driver是java.sql包里定义的两个接口;DriverManager是java.sql包里定义的一个类;如何启动mysql驱动程序的呢?com.mysql.jdbc.Driver是mysql-connector-java.jar里定义的一个类;这里使用了反射机制,照说应该写成Class clazz=Class.forName("com.mysql.jdbc.Driver");
然后在创建实例,再调用实例的某个方法来启动数据库,比如这样:clazz.newInstace().method();  这里看看com.mysql.jdbc.Driver的源码是怎么写的,好像现在下载不到源码,使用反编译器jd-gui查看:
public class Driver extends NonRegisteringDriver{ 
    public Driver() throws SQLException{} 
    static { 
        try{ 
            DriverManager.registerDriver(new Driver());       
        } 
        catch(SQLException E){ 
            throw new RuntimeException("Can't register driver!"); 
        } 
    } 
} 
在Driver的构造方法里声明了static关键字,也就是说在Class.forName的时候,1.构造方法没有执行,2.执行DriverManager.registerDriver方法,3.执行registerDriver为什么里面是new Driver()而不是this呢?
解决这个问题  看我的第2章、类与对象关于方法的执行顺序;因为直接执行了静态块,该对象还没创建一个堆内存空间,this指向的是个null,jvm会报空指针异常;这里查看到NonRegisteringDriver 实现了Driver接口:


再看看DriverManager.registerDriver()这个方法:
 public static synchronized void registerDriver(java.sql.Driver driver)
        throws SQLException {
        if(driver != null) {
            registeredDrivers.addIfAbsent(new DriverInfo(driver));
         } else {
            throw new NullPointerException();
        }
 执行上一步,就是为连接做好了准备,在DriverManager(驱动器管理者)这里注册登记了,以后就可以使用了; 需要更换数据库只需要更改发射机制提供的地址:
Class.forName("oracle.jdbc.driver.OracleDriver");
public class OracleDriver  implements Driver{... ...}//同样里面也是有static{DriverManager.registerDriver()}方法
 
2.6、Composite(组件模式)  组合模式有时又叫部分-整体模式在处理类似树形结构的问题时比较方便;
2.7、Flyweight(享元模式)
享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。 当一个客户端请求时,工厂需要检查当前对象池中是否有符合条件的对象,如果有,就返回已经存在的对象,如果没有,则创建一个新对象;又如 Java里面的JDBC连接池,url、driverClassName、username、password及dbname,这些属性对于每个连接来说都是一样的,所以就适合用享元模式来处理,建一个工厂类,将上述类似属性作为内部数据,其它的作为外部数据,在方法调用时,当做参数传进来,这样就节省了空间,减少了实例的数量。
/*公有属性*/  
    private String url = "jdbc:mysql://localhost:3306/test";  
    private String username = "root";  
    private String password = "root";  
    private String driverClassName = "com.mysql.jdbc.Driver";  
	
private Vector<Connection> pool;
public ConnectionPool(int poolSize) throw Exception{  
        pool = new Vector<Connection>(poolSize);    
        for (int i = 0; i < poolSize; i++) {  
                Class.forName(driverClassName);  
                conn = DriverManager.getConnection(url, username, password);  
                pool.add(conn);    
        }   
}
 通过设置Vector/List集合里的实列数量,来动态实现最大、最小、初始、闲置的数据库连接数量;
下章接着讲解设计模式的行为模式;
 
Connection、Driver是java.sql包里定义的两个接口;DriverManager是java.sql包里定义的一个类;如何启动mysql驱动程序的呢?com.mysql.jdbc.Driver是mysql-connector-java.jar里定义的一个类;这里使用了反射机制,照说应该写成Class clazz=Class.forName("com.mysql.jdbc.Driver"); 然后在创建实例,再调用实例的某个方法来启动数据库,比如这样:clazz.newInstace().method();  这里看看com.mysql.jdbc.Driver的源码是怎么写的,好像现在下载不到源码,使用反编译器jd-gui查看:
public class Driver extends NonRegisteringDriver{ 
    public Driver() throws SQLException{} 
    static { 
        try{ 
            DriverManager.registerDriver(new Driver());       
        } 
        catch(SQLException E){ 
            throw new RuntimeException("Can't register driver!"); 
        } 
    } 
} 
在Driver的构造方法里声明了static关键字,也就是说在Class.forName的时候,1.构造方法没有执行,2.执行DriverManager.registerDriver方法,3.执行registerDriver为什么里面是new Driver()而不是this呢? 解决这个问题  看我的第2章、类与对象关于方法的执行顺序;因为直接执行了静态块,该对象还没创建一个堆内存空间,this指向的是个null,jvm会报空指针异常;这里查看到NonRegisteringDriver 实现了Driver接口:


再看看DriverManager.registerDriver()这个方法:
 public static synchronized void registerDriver(java.sql.Driver driver)
        throws SQLException {
        if(driver != null) {
            registeredDrivers.addIfAbsent(new DriverInfo(driver));
         } else {
            throw new NullPointerException();
        }
 执行上一步,就是为连接做好了准备,在DriverManager(驱动器管理者)这里注册登记了,以后就可以使用了; 需要更换数据库只需要更改发射机制提供的地址:
Class.forName("oracle.jdbc.driver.OracleDriver");
public class OracleDriver  implements Driver{... ...}//同样里面也是有static{DriverManager.registerDriver()}方法
  2.6、Composite(组件模式)  组合模式有时又叫部分-整体模式在处理类似树形结构的问题时比较方便; 2.7、Flyweight(享元模式) 享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。 当一个客户端请求时,工厂需要检查当前对象池中是否有符合条件的对象,如果有,就返回已经存在的对象,如果没有,则创建一个新对象;又如 Java里面的JDBC连接池,url、driverClassName、username、password及dbname,这些属性对于每个连接来说都是一样的,所以就适合用享元模式来处理,建一个工厂类,将上述类似属性作为内部数据,其它的作为外部数据,在方法调用时,当做参数传进来,这样就节省了空间,减少了实例的数量。
/*公有属性*/  
    private String url = "jdbc:mysql://localhost:3306/test";  
    private String username = "root";  
    private String password = "root";  
    private String driverClassName = "com.mysql.jdbc.Driver";  
	
private Vector<Connection> pool;
public ConnectionPool(int poolSize) throw Exception{  
        pool = new Vector<Connection>(poolSize);    
        for (int i = 0; i < poolSize; i++) {  
                Class.forName(driverClassName);  
                conn = DriverManager.getConnection(url, username, password);  
                pool.add(conn);    
        }   
}
 通过设置Vector/List集合里的实列数量,来动态实现最大、最小、初始、闲置的数据库连接数量; 下章接着讲解设计模式的行为模式;  

猜你喜欢

转载自nickfover.iteye.com/blog/2122870