设计模式之结构型模式
结构型模式主要分为七大类:适配器模式(Adapter pattern)、装饰器模式(Decorator pattern)、代理模式(Proxy pattern)、外观模式(Facade pattern)、桥接模式(Bridge pattern)、组合模式(composite pattern)、享元模式(Flyweight Pattern)
一、适配器模式(Adapter pattern)
适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。
1、类的适配器模式:有一个Source类,拥有一个方法,待适配,目标接口时Targetable,通过Adapter类,将Source的功能扩展到Targetable里
public class Source { public void method1(){ System.out.println("this is method1"); } } public interface Targetable { void method1(); void method2(); } public class Adapter extends Source implements Targetable{ @Override public void method2() { System.out.println("this is method2"); } } //测试 public class ApdapterTest { public static void main(String[] args) { Targetable target = new Adapter(); target.method1(); target.method2(); } }
2、对象的适配器模式:与类的适配器模式基本相同,只是适配器不再继承Source类而是持有Source类的对象。
public class Adapter implements Targetable{ private Source source; public Adapter (Source source){ this.source = source; } @Override public void method2() { System.out.println("this is method2"); } @Override public void method1() { source.method1(); } } public class ApdapterTest { public static void main(String[] args) { Source source = new Source(); Targetable target = new Adapter(source); target.method1(); target.method2(); } }
3、接口的适配器模式:有时候某个接口定义的方法太多,但是我们有些类又不需要这么多方法,那就先定一个抽象类来实现接口的所有方法,然后我们再去继承该抽象类,重写我们需要的方法。
public interface Sourceable { void method1(); void method2(); } public abstract class Wrapper implements Sourceable { @Override public void method1() { } @Override public void method2() { } } public class SourceSub extends Wrapper { @Override public void method1() { System.out.println("this is method1"); } } public class WrapperTest { public static void main(String[] args) { Sourceable ss = new SourceSub(); ss.method1(); } }
二、装饰器模式(Decorator pattern)
装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例
public interface Sourceable { void method(); } public class Source implements Sourceable { @Override public void method() { System.out.println("this is source method"); } } public class Decorator implements Sourceable { private Source Source; public Decorator(Source source){ this.Source = source; }; @Override public void method() { System.out.println("before method"); Source.method(); System.out.println("after method"); } } public class DecoratorTest { public static void main(String[] args) { Source souce = new Source(); Decorator decorator = new Decorator(souce); decorator.method(); } }
三、代理模式(Proxy pattern)
代理是一种模式,提供了对目标对象的间接访问方式,即通过代理访问目标对象。在不改变目标对象实现的基础上增加额外的功能操作等,以满足自身的业务需求,同时代理模式便于扩展目标对象功能的特点也为多人所用。代理模式主要分为静态代理和动态代理两类。
1、静态代理:静态代理的代理类是直接将代理类编写出来,在运行期不会有变化。静态代理和装饰者模式两者代码非常相近,但是所表达的含义确是不同的。装饰者模式强调的是对原对象的功能的增强,而代理模式强调的是对原对象的访问控制。
所以静态代理中原对象一般都是直接在代理类中创建出来,而装饰者模式中对象一般都是将原对象作为装饰者对象的构造函数的参数传入。
public interface Sourceable { void method(); } public class Source implements Sourceable { @Override public void method() { System.out.println("this is source method"); } } public class Proxy implements Sourceable { private Source Source; public Proxy(){ this.Source = new Source(); }; @Override public void method() { System.out.println("before method"); Source.method(); System.out.println("after method"); } } public class ProxyTest { public static void main(String[] args) { Sourceable proxy = new Proxy(); proxy.method(); } }
2、动态代理:动态代理是指动态的在内存中构建代理对象,也称之为JDK代理或者接口代理。
public interface Sourceable { void method(); } public class Source implements Sourceable { @Override public void method() { System.out.println("this is source method"); } } //第一种动态代理写法 public class ProxyFactory{ private Sourceable source; public ProxyFactory(){ this.source = new Source(); }; public Sourceable getProxyInstance(){ return (Sourceable)Proxy.newProxyInstance( source.getClass().getClassLoader(), source.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before method"); Object result = method.invoke(source, args); System.out.println("after method"); return result; } }); } } //第二种动态代理写法,其实和第一中是一样的 public class SourceProxy implements InvocationHandler{ private Sourceable source = new Source(); public Sourceable getSourceProxy(){ return (Sourceable)Proxy.newProxyInstance(source.getClass().getClassLoader(), source.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before method"); Object result = method.invoke(source, args); System.out.println("after method"); return result; } } //测试动态代理 public class ProxyTest { public static void main(String[] args) { ProxyFactory proxyFactory = new ProxyFactory(); Sourceable proxy = proxyFactory.getProxyInstance(); proxy.method(); System.out.println("===="); SourceProxy sourceProxy = new SourceProxy(); Sourceable proxy2 = sourceProxy.getSourceProxy(); proxy2.method(); } }
四、外观模式(Facade pattern)
隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。
public class CPU { public void startup(){ System.out.println("cpu startup!"); } public void shutdown(){ System.out.println("cpu shutdown!"); } } public class Memory { public void startup(){ System.out.println("memory startup!"); } public void shutdown(){ System.out.println("memory shutdown!"); } } public class Disk { public void startup(){ System.out.println("disk startup!"); } public void shutdown(){ System.out.println("disk shutdown!"); } } public class Computer { private CPU cpu; private Memory memory; private Disk disk; public Computer(){ cpu = new CPU(); memory = new Memory(); disk = new Disk(); } public void startup(){ System.out.println("start the computer!"); cpu.startup(); memory.startup(); disk.startup(); System.out.println("start computer finished!"); } public void shutdown(){ System.out.println("begin to close the computer!"); cpu.shutdown(); memory.shutdown(); disk.shutdown(); System.out.println("computer closed!"); } } public class FacadeTest{ public static void main(String[] args) { Computer computer = new Computer(); computer.startup(); computer.shutdown(); } }
五、桥接模式(Bridge pattern)
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。经典例子就是jDBC 加载数据库驱动
public interface Sourceable { void method(); } public class SourceSub1 implements Sourceable { @Override public void method() { System.out.println("this is SourceSub1"); } } public class SourceSub2 implements Sourceable { @Override public void method() { System.out.println("this is SourceSub2"); } } public abstract class Bridge { private Sourceable source; public void method(){ source.method(); } public Sourceable getSource() { return source; } public void setSource(Sourceable source) { this.source = source; } } public class MyBridge extends Bridge { public void method(){ getSource().method(); } } public class BridgeTest { public static void main(String[] args) { Bridge bridge = new MyBridge(); /*调用第一个对象*/ Sourceable source1 = new SourceSub1(); bridge.setSource(source1); bridge.method(); /*调用第二个对象*/ Sourceable source2 = new SourceSub2(); bridge.setSource(source2); bridge.method(); } }
六、组合模式(composite pattern)
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。经典例子就是部门树形结构
public class Department { private Long id; private Long pid; private String name; private List<Department> childDepartments = new ArrayList<Department>(); public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Long getPid() { return pid; } public void setPid(Long pid) { this.pid = pid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Department> getChildDepartments() { return childDepartments; } public void setChildDepartments(List<Department> childDepartment) { this.childDepartments = childDepartment; } }
七、享元模式(Flyweight Pattern)
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能,它提供了减少对象数量从而改善应用所需的对象结构的方式。
public class ConnectionPool { private ConnectionPool(){} private static final Vector<Connection> pool; /*公有属性*/ private static String url = "jdbc:mysql://localhost:3306/zmyproject"; private static String username = "root"; private static String password = "root"; private static String driverClassName = "com.mysql.jdbc.Driver"; private static int poolSize = 15; static { pool = new Vector<Connection>(poolSize); for (int i = 0; i < poolSize; i++) { try { Class.forName(driverClassName); Connection conn = DriverManager.getConnection(url, username, password); pool.add(conn); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } } /* 返回连接到连接池 */ public static synchronized void release(Connection connection) { pool.add(connection); } /* 返回连接池中的一个数据库连接 */ public static synchronized Connection getConnection() { if (pool.size() > 0) { Connection conn = pool.get(0); pool.remove(conn); return conn; } else { return null; } } }