前言
本篇文章主要讲23种设计模式中的7种结构型设计模式,包括适配器模式,装饰者模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
适配器模式
适配器模式是将一个类的方法接口转换成客户端期望的接口表示。我们可以约定,把客户端期望的接口叫做目标Targetable,被转换的类叫source。适配器模式可以分为:类的适配器模式,对象的适配器,接口的适配器。
类的适配器模式
已有的被转换的类:
1 2 3 4 5 6 7
| public class SourceClass {
public void method1() { System.out.print("Hi, I am a method in sourceClass"); }
}
|
期望的目标:
1 2 3 4
| public interface Targetable { void method1(); void method2(); }
|
实现目标,进行适配
1 2 3 4 5 6 7
| public class AdapterClass extends SourceClass implements Targetable {
@Override public void method2() { System.out.print("Hi All, I am a method in adapterClass"); } }
|
这样子就将SourceClass按照意愿Targetable适配转换成了AdapterClass,AdapterClass具有了SourceClass的所有的功能,同时也达到了扩展SourceClass。由于类的适配器模式是通过继承实现的,它具有了继承的优缺点。关于缺点,比如通过AdapterClass对象可以调用属于SourceClass而在Targetable接口中没有的方法。
对象的适配器模式
对象的适配器模式,就是将原来类的对象转换为目标接口的对象。对象适配器模式没有继承被转换类,而是持有被转换类的对象。这可以避免继承被带来的副作用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class AdapterObjectClass implements Targetable{
private SourceClass mSourceClass;
public AdapterObjectClass(SourceClass mSourceClass) { this.mSourceClass = mSourceClass; }
@Override public void method2() { System.out.print("hi all, i am a method in AdapterObjectClass"); }
@Override public void method1() { mSourceClass.method1(); } }
|
接口的适配器模式
当一个接口有很多的抽象方法时,当我们写这个接口的实现类,必须实现该接口的全部方法。而有时候接口中并不是所有的抽象方法都是我们必须的,而我们只需要实现其中的某一些方法。为了解决这个问题,我们可以使用接口的适配器模式,引入一个抽象类,这个抽象类提供了接口所有抽象方法的空实现。我们可以继承这个抽象类,并只重写我们需要的方法即可。
比如,在上面我们只要Targetable的method2方法。
1 2 3 4 5 6 7 8 9 10 11 12
| public abstract class AdapterInterfaceClass implements Targetable{
@Override public void method1() {
}
@Override public void method2() {
} }
|
1 2 3 4 5 6 7
| public class AdapterWraper extends AdapterInterfaceClass {
@Override public void method1() { System.out.print("hi all, I am a method in AdapterWraper class"); } }
|
装饰者模式
装饰者模式的核心思想是,装饰者和被装饰者实现同一个接口,将被装饰者注入装饰者中,可以在装饰者中扩展被装饰者。
1 2 3
| public interface Person { void eat(); }
|
被装饰者:
1 2 3 4 5 6 7
| public class Man implements Person {
@Override public void eat() { System.out.print("There is a man who is eating"); } }
|
装饰者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class ManDecorator implements Person {
private Person mPerson;
public ManDecorator(Person person) { mPerson = person; }
@Override public void eat() { mPerson.eat(); drinkWater(); System.out.print("I finish my lunch"); }
private void drinkWater() { System.out.print("Man is drinking water"); } }
|
使用:
1 2 3
| Man man = new Man(); ManDecorator manDecorator = new ManDecorator(man); manDecorator.eat();
|
输出的结果:
1 2 3
| There is a man who is eating Man is drinking water I finish my lunch
|
代理模式
注意区别代理模式和动态代理。
生活中代理的例子。比如如果你要租房子,你可能不知道该地区的房子信息,这时你可以找一个熟悉的人来帮忙,这个帮你的人就是代理;又比如,打官司时,我们可能并不精通法律知识,这时我们可以找一个代理律师来帮我们。等等。。对于,代理的工作可以抽象为一个接口。
1 2 3
| public interface WorkInterface { void rentHouse(); }
|
一个房东:
1 2 3 4 5 6 7
| public class LandLady implements WorkInterface {
@Override public void rentHouse() { System.out.print("您好!我是房东。我这里有房子出租!"); } }
|
代理房东的代理类:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Proxy implements WorkInterface {
private LandLady mLandLady;
public Proxy() { mLandLady = new LandLady(); }
@Override public void rentHouse() { mLandLady.rentHouse(); } }
|
租客去找代理租房子:
1 2
| WorkInterface proxy = new Proxy(); proxy.rentHouse();
|
外观模式
在医院里的前台接待员就是一个外观模式的体现。由于病人来到医院可能对医院内部和流程并不熟悉,那么可以由熟悉这些的接待员来帮病人来完成这些事情。
部门1
1 2 3 4 5 6 7 8 9
| public class ModuleA {
//提供给外部调用的方法 public void a1() {}
//内部完成工作的实现 private void a2() {} private void a3() {} }
|
部门2
1 2 3 4 5 6 7 8 9
| public class ModuleB {
//提供给外部调用的方法 public void b1() {}
//内部完成工作的实现 private void b2() {} private void b3() {} }
|
部门3
1 2 3 4 5 6 7 8 9
| public class ModuleC {
//提供给外部调用的方法 public void c1() {}
//内部完成工作的实现 private void c2() {} private void c3() {} }
|
外观类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class ModuleFacade {
private ModuleA mModuleA = new ModuleA(); private ModuleB mMBModuleB = new ModuleB(); private ModuleC mMCModuleC = new ModuleC();
public void a1() { mModuleA.a1(); }
public void b1() { mMBModuleB.b1(); }
public void c1() { mMCModuleC.c1(); }
}
|
当我们需要ModuleA,ModuleB, ModuleC的功能时,我们并不直接和他们打交道,也不需要了解部门的功能是如何实现的,而我们只需要去找外观类沟通即可。
外观模式的关键点是整合。
桥接模式
桥接模式,提供一个解耦或者连接抽象化和实现化的一个桥梁,使得二者可以独立变化。
一个接口作为桥,一个抽象类持有桥。桥和抽象类两者可以独立变化。
桥:
1 2 3
| public interface Qiao { void toArea(); }
|
抽象类:
1 2 3 4
| public abstract class FromArea { public Qiao qiao; abstract public void fromArea(); }
|
QiaoC.java
1 2 3 4 5 6 7
| public class QiaoC implements Qiao {
@Override public void toArea() { System.out.print("I want to go Area C"); } }
|
QiaoD.java
1 2 3 4 5 6 7
| public class QiaoD implements Qiao {
@Override public void toArea() { System.out.print("I want to go Area D"); } }
|
FromAreaA.java
1 2 3 4 5 6 7
| public class FromAreaA extends FromArea {
@Override public void fromArea() { System.out.print("I come from area A"); } }
|
FromAreaB.java
1 2 3 4 5 6 7
| public class FromAreaB extends FromArea {
@Override public void fromArea() { System.out.print("I come from area B"); } }
|
使用:
1 2 3 4 5 6 7 8 9 10 11 12
| FromAreaA fromAreaA = new FromAreaA(); QiaoC qiaoC = new QiaoC(); fromAreaA.qiao = qiaoC;
fromAreaA.fromArea(); fromAreaA.qiao.toArea();
QiaoD qiaoD = new QiaoD(); fromAreaA.qiao = qiaoD;
fromAreaA.fromArea(); fromAreaA.qiao.toArea();
|
从上面可以看出,Qiao和FromArea两者是独立变化的,它们的抽象和实现是分离的。
如果有更多的Qiao和FromArea的实现,只要扩展它们即可。
组合模式
组合模式,又叫“整体-部分设计模式”。它一般用于实现树形结构。
节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class TreeNode {
private String name; private TreeNode parent; private Vector<TreeNode> children = new Vector<>();
public TreeNode(String name) { this.name = name; }
public void setName(String name) { this.name = name; }
public String getName() { return name; }
public void setParent(TreeNode parent) { this.parent = parent; }
public TreeNode getParent() { return parent; }
public void addChild(TreeNode child) { children.add(child); }
public boolean removeChild(TreeNode child) { return children.remove(child); }
public Enumeration<TreeNode> getChildren() { return children.elements(); }
}
|
整体,建立一棵树:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Tree { TreeNode root = null;
public Tree(String name) { root = new TreeNode(name); }
public static void main(String[] args) { Tree tree = new Tree("A"); TreeNode nodeB = new TreeNode("B"); TreeNode nodeC = new TreeNode("C");
nodeB.addChild(nodeC); tree.root.addChild(nodeB); System.out.println("build the tree finished!"); } }
|
享元模式
享元模式主要是实现对象的共享。联想数据库的连接池。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| public class ConnectionPool { private Vector<Connection> pool; /*公有属性*/ private String url = "jdbc:mysql://localhost:3306/test"; private String username = "root"; private String password = "root"; private String driverClassName = "com.mysql.jdbc.Driver"; private int poolSize = 100; private static ConnectionPool instance = null; Connection conn = null; /*构造方法,做一些初始化工作*/ private ConnectionPool() { pool = new Vector<Connection>(poolSize); for (int i = 0; i < poolSize; i++) { try { Class.forName(driverClassName); conn = DriverManager.getConnection(url, username, password); pool.add(conn); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } } /* 返回连接到连接池 */ public synchronized void release() { pool.add(conn); } /* 返回连接池中的一个数据库连接 */ public synchronized Connection getConnection() { if (pool.size() > 0) { Connection conn = pool.get(0); pool.remove(conn); return conn; } else { return null; } } }
|