目录
一、设计原则
1、单一职责原则
一个类只负责一个功能领域中的相应职责
2、开闭原则
一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
3、氏代换原则
在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。例如:我喜欢动物,那我一定喜欢狗,因为狗是动物的子类;但是我喜欢狗,不能据此断定我喜欢动物,因为我并不喜欢老鼠,虽然它也是动物。
4、依赖倒转原则
在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情
5、接口隔离原则
使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。这里的“接口”往往有两种不同的含义:
-
理解成一个类型所提供的所有方法特征的集合:这就是一种逻辑上的概念,接口的划分将直接带来类型的划分。可以把接口理解成角色,一个接口只能代表一个角色,每个角色都有它特定的一个接口,此时,这个原则可以叫做“角色隔离原则”。
-
解成狭义的特定语言的接口:比如Java语言中的interface
6、合成复用原则
尽量使用对象组合,而不是继承来达到复用的目的。
7、迪米特法则
一个软件实体应当尽可能少地与其他实体发生相互作用。当其中某一个模块发生修改时,就会尽量少地影响其他模块
二、创建型模式
1、简单工厂模式
是工厂方法模式的小弟,不属于23种设计模式的其中一种。
-
定义:
定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式。
-
特点:
当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节
-
角色:
-
Factory(工厂角色):工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方法factoryMethod(),它的返回类型为抽象产品类型Product。
-
Product(抽象产品角色):它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。
-
ConcreteProduct(具体产品角色):它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法。
-
-
缺点:
-
当系统中需要引入新产品时,由于静态工厂方法通过所传入参数的不同来创建不同的产品,这必定要修改工厂类的源代码,将违背“开闭原则”
-
所有的产品都由同一个工厂创建,工厂类职责较重,业务逻辑较为复杂,具体产品与工厂类之间的耦合度高,严重影响了系统的灵活性和扩展性
-
-
案例:
//抽象图表接口:抽象产品类 interface Chart { public void display(); } //柱状图类:具体产品类 class HistogramChart implements Chart { public HistogramChart() { System.out.println("创建柱状图!"); } public void display() { System.out.println("显示柱状图!"); } } //饼状图类:具体产品类 class PieChart implements Chart { public PieChart() { System.out.println("创建饼状图!"); } public void display() { System.out.println("显示饼状图!"); } } //折线图类:具体产品类 class LineChart implements Chart { public LineChart() { System.out.println("创建折线图!"); } public void display() { System.out.println("显示折线图!"); } } //图表工厂类:工厂类 class ChartFactory { //静态工厂方法 public static Chart getChart(String type) { Chart chart = null; if (type.equalsIgnoreCase("histogram")) { chart = new HistogramChart(); System.out.println("初始化设置柱状图!"); } else if (type.equalsIgnoreCase("pie")) { chart = new PieChart(); System.out.println("初始化设置饼状图!"); } else if (type.equalsIgnoreCase("line")) { chart = new LineChart(); System.out.println("初始化设置折线图!"); } return chart; } }
2、工厂方法模式
-
定义:
定义一个用于创建对象的接口,让子类决定将哪一个类实例化。
-
角色:
-
Product(抽象产品):它是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类。
-
ConcreteProduct(具体产品):它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应。
-
Factory(抽象工厂):在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个产品。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口。抽象工厂可以是接口,也可以是抽象类或者具体类
-
ConcreteFactory(具体工厂):它是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户端调用,返回一个具体产品类的实例。
-
-
缺点:
-
每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。
-
-
案例:
//日志记录器接口:抽象产品 interface Logger { public void writeLog(); } //数据库日志记录器:具体产品 class DatabaseLogger implements Logger { public void writeLog() { System.out.println("数据库日志记录。"); } } //文件日志记录器:具体产品 class FileLogger implements Logger { public void writeLog() { System.out.println("文件日志记录。"); } } //日志记录器工厂接口:抽象工厂 interface LoggerFactory { public Logger createLogger(); } //数据库日志记录器工厂类:具体工厂 class DatabaseLoggerFactory implements LoggerFactory { public Logger createLogger() { //连接数据库,代码省略 //创建数据库日志记录器对象 Logger logger = new DatabaseLogger(); //初始化数据库日志记录器,代码省略 return logger; } } //文件日志记录器工厂类:具体工厂 class FileLoggerFactory implements LoggerFactory { public Logger createLogger() { //创建文件日志记录器对象 Logger logger = new FileLogger(); //创建文件,代码省略 return logger; } }
3、抽象工厂模式
产品继承结构:如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
产品族:指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱等。
-
定义:
提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式中的具体工厂不只是创建一种产品,而是负责创建一族产品。
-
角色:
-
AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
-
ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
-
AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
-
ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
-
-
缺点:
-
增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。
-
-
案例:
//按钮接口:抽象产品 interface Button { public void display(); } //Spring按钮类:具体产品 class SpringButton implements Button { public void display() { System.out.println("显示浅绿色按钮。"); } } //Summer按钮类:具体产品 class SummerButton implements Button { public void display() { System.out.println("显示浅蓝色按钮。"); } } //文本框接口:抽象产品 interface TextField { public void display(); } //Spring文本框类:具体产品 class SpringTextField implements TextField { public void display() { System.out.println("显示绿色边框文本框。"); } } //Summer文本框类:具体产品 class SummerTextField implements TextField { public void display() { System.out.println("显示蓝色边框文本框。"); } } //组合框接口:抽象产品 interface ComboBox { public void display(); } //Spring组合框类:具体产品 class SpringComboBox implements ComboBox { public void display() { System.out.println("显示绿色边框组合框。"); } } //Summer组合框类:具体产品 class SummerComboBox implements ComboBox { public void display() { System.out.println("显示蓝色边框组合框。"); } } //界面皮肤工厂接口:抽象工厂 interface SkinFactory { public Button createButton(); public TextField createTextField(); public ComboBox createComboBox(); } //Spring皮肤工厂:具体工厂 class SpringSkinFactory implements SkinFactory { public Button createButton() { return new SpringButton(); } public TextField createTextField() { return new SpringTextField(); } public ComboBox createComboBox() { return new SpringComboBox(); } } //Summer皮肤工厂:具体工厂 class SummerSkinFactory implements SkinFactory { public Button createButton() { return new SummerButton(); } public TextField createTextField() { return new SummerTextField(); } public ComboBox createComboBox() { return new SummerComboBox(); } }
4、单例模式
-
构造方法私有化,不能让外部通过new的方式来创建对象。
-
提供一个静态方法,用于获取该实例对象
饿汉式:类一旦加载就会创建对象,浪费空间;相对不安全,可以被反射机制、序列化操作破坏。
- 静态常量 :
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {}
public static Singleton getSingleton() {
return singleton;
}
}
-
静态代码块:
class Singleton{ private Singleton(){}; public static Singleton singleton; static{ singleton = new Singleton(); } public static Singleton getSingleton() { return singleton; } }
懒汉式:当调用getInstance方法时才会创建对象,不浪费空间;相对不安全,可以被反射机制、序列化操作破坏
-
双重检查:
//JVM底层实现:1、new Singleton() 2、执行构造方法 3、singleton =对象 //其中2和3是可以互换顺序的。如果先执行3后执行2 则线程1放弃CPU执行权,线程2获取CPU执行权,就会导致创建不同的对象。 public class Singleton { //volatile:1、有序性(在这里的作用是防止JVM指令重拍)2、可见性 private static volatile Singleton singleton; private Singleton() {} public static Singleton getInstance() { //第一重判断 if (singleton == null) { //锁定代码块 synchronizedd (Singleton.class) { //第二重判断 if (singleton == null) { singleton = new Singleton();创建单例实例 } } } return singleton; } }
内部类:内部类不会随着外部类的加载而加载,内部类只有在使用到的时候,才会加载,不浪费空间;相对不安全,可以被反射机制、序列化操作破坏
public class Holder {
private Holder(){}
public static Holder getInstance(){
return InnerClass.test1;
}
public static class InnerClass{
private static final Holder test1 = new Holder();
}
}
枚举类:相对安全,不可以被反射机制、序列化操作破坏
enum Instance{
INSTANCE;
}
三、结构型
1、适配器模式
-
定义:
将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。
-
共同优点:
-
将目标类和适配者类解耦
-
增加了类的透明性和复用性
-
灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器
-
-
对象适配器:适配器与适配者之间是关联关系
-
优点:一个对象适配器可以把多个不同的适配者适配到同一个目标
-
案例:
class Adapter extends Target { private Adaptee adaptee; //维持一个对适配者对象的引用 public Adapter(Adaptee adaptee) { this.adaptee=adaptee; } public void request() { adaptee.specificRequest(); //转发调用 } }
-
角色:
-
Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。
-
Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。
-
Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。
-
-
-
类适配器:适配器与适配者之间是继承(或实现)关系
-
适配器类实现了抽象目标类接口Target,并继承了适配者类,在适配器类的request()方法中调用所继承的适配者类的specificRequest()方法,实现了适配。
class Adapter extends Adaptee implements Target { public void request() { specificRequest(); } }
-
优点:在适配器类中置换一些适配者的方法,使得适配器的灵活性更强
-
缺点:
-
Java支持单继承,多实现,所以一次最多只能适配一个适配者类,不能同时适配多个适配者
-
适配者类不能为最终类,如在Java中不能为final类
-
目标抽象类只能为接口,不能为类
-
-
-
应用:Spring MVC 中的 HandlerAdapter 类
2、代理模式
-
定义:
-
给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问
-
代理对象在客户端对象和目标对象之间起到中介的作用,它去掉客户不能看到的内容和服务或者增添客户需要的额外的新服务
-
-
角色:
-
Subject(抽象角色):它声明了真实主题和代理主题的共同接口,这样一来在任何使用真实主题的地方都可以使用代理主题,客户端通常需要针对抽象主题角色进行编程。
-
Proxy(代理角色):它包含了对真实主题的引用,从而可以在任何时候操作真实主题对象;在代理主题角色中提供一个与真实主题角色相同的接口,以便在任何时候都可以替代真实主题;代理主题角色还可以控制对真实主题的使用,负责在需要的时候创建和删除真实主题对象,并对真实主题对象的使用加以约束。通常,在代理主题角色中,客户端在调用所引用的真实主题操作之前或之后还需要执行其他操作,而不仅仅是单纯调用真实主题对象中的操作。
-
RealSubject(真实角色):它定义了代理角色所代表的真实对象,在真实主题角色中实现了真实的业务操作,客户端可以通过代理主题角色间接调用真实主题角色中定义的操作。
-
-
静态代理:
-
需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者继承相同的父类
-
优点:在不修改目标对象代码的情况下,能够通过代理对象对目标功能拓展
-
缺点:因为每次代理对象的创建都需要与目标对象实现一样的接口,所以会产生很多的代理类,而且一旦接口增加了方法,目标对象和代理对象都需要进行维护。
-
-
动态代理:
-
代理类编写时不指定被代理的类是谁,代理类是动态生成的,通过java反射机制,在运行时获取某个目标类的接口,并创建代理类
-
基于接口的JDK动态代理:
-
代理对象不需要实现接口,但是目标对象需要实现接口。
-
代理对象生成是利用JDK的API,通过反射的方式动态的在内存中构建代理对象
-
-
基于类的Cglib动态代理:
-
在内存中构建子类,但是代理对象不能为final,目标方法不能为final/static
-
-
3、装饰者模式
-
角色:
-
Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。
-
ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象
构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
-
Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
-
ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。
-
-
案例:
//抽象界面构件类:抽象构件类,为了突出与模式相关的核心代码,对原有控件代码进行了大量的简化 abstract class Component{ public abstract void display(); } //窗体类:具体构件类 class Window extends Component{ public void display(){ System.out.println("显示窗体!"); } } //文本框类:具体构件类 class TextBox extends Component{ public void display(){ System.out.println("显示文本框!"); } } //列表框类:具体构件类 class ListBox extends Component{ public void display(){ System.out.println("显示列表框!"); } } //构件装饰类:抽象装饰类 class ComponentDecorator extends Component{ private Component component; //维持对抽象构件类型对象的引用 public ComponentDecorator(Component component){ //注入抽象构件类型的对象 this.component = component; } public void display(){ component.display(); } } //滚动条装饰类:具体装饰类 class ScrollBarDecorator extends ComponentDecorator{ public ScrollBarDecorator(Component component){ super(component); } public void display(){ this.setScrollBar(); super.display(); } public void setScrollBar(){ System.out.println("为构件增加滚动条!"); } } //黑色边框装饰类:具体装饰类 class BlackBorderDecorator extends ComponentDecorator{ public BlackBorderDecorator(Component component){ super(component); } public void display(){ this.setBlackBorder(); super.display(); } public void setBlackBorder(){ System.out.println("为构件增加黑色边框!"); } }
-
应用:
-
JDK中的I/O,如BufferReader、InputStream、OutputStream
-
Spring的缓存
-
myabtis的TransactionalCache
-
四、行为型
1、职责链模式
2、命令模式
3、迭代器模式
4、观察者模式
在JDK的java.util包中,提供了Observable类以及Observer接口,它们构成了JDK对观察者模式的支持.
Observer接口:当一个类想要被通知可观察对象的变化时,它可以实现Observer接口
public interface Observer {
//每当观察到的对象发生变化时,都会调用此方法。应用程序调用Observable对象的notifyObservers方 法来通知对象的所有观察者更改
void update(Observable o, Object arg);
}
Observable类:此类表示可观察对象。它可以被子类化以表示应用程序想要观察的对象。
在Observable中定义了一个向量Vector来存储观察者对象,并且里面包含了一系列的操作观察者的方法
角色:
-
Subject(目标):目标又称为主题,它是指被观察的对象。在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify()。目标类可以是接口,也可以是抽象类或具体类。
-
ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。
-
Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者。
-
ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法。通常在实现时,可以调用具体目标类的attach()方法将自己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除。
-
案例:
import java.util.*; /** 抽象观察类 */ interface Observer { public String getName(); public void setName(String name); public void help(); //声明支援盟友方法 public void beAttacked(AllyControlCenter acc); //声明遭受攻击方法 } /** 战队成员类:具体观察者类 */ class Player implements Observer { private String name; public Player(String name) { this.name = name; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } //支援盟友方法的实现 public void help() { System.out.println("坚持住," + this.name + "来救你!"); } //遭受攻击方法的实现,当遭受攻击时将调用战队控制中心类的通知方法notifyObserver()来通知盟友 public void beAttacked(AllyControlCenter acc) { System.out.println(this.name + "被攻击!"); acc.notifyObserver(name); } } /** 战队控制中心类:目标类 */ abstract class AllyControlCenter { protected String allyName; //战队名称 protected ArrayList<Observer> players = new ArrayList<Observer>(); //定义一个集合用于存储战队成员 public void setAllyName(String allyName) { this.allyName = allyName; } public String getAllyName() { return this.allyName; } //注册方法 public void join(Observer obs) { System.out.println(obs.getName() + "加入" + this.allyName + "战队!"); players.add(obs); } //注销方法 public void quit(Observer obs) { System.out.println(obs.getName() + "退出" + this.allyName + "战队!"); players.remove(obs); } //声明抽象通知方法 public abstract void notifyObserver(String name); } /** 具体战队控制中心类:具体目标类 */ class ConcreteAllyControlCenter extends AllyControlCenter { public ConcreteAllyControlCenter(String allyName) { System.out.println(allyName + "战队组建成功!"); System.out.println("----------------------------"); this.allyName = allyName; } //实现通知方法 public void notifyObserver(String name) { System.out.println(this.allyName + "战队紧急通知,盟友" + name + "遭受敌人攻击!"); //遍历观察者集合,调用每一个盟友(自己除外)的支援方法 for(Object obs : players) { if (!((Observer)obs).getName().equalsIgnoreCase(name)) { ((Observer)obs).help(); } } } }
-
应用:
-
在当前流行的MVC(Model-View-Controller)架构中,MVC是一种架构模式,它包含三个角色:模型(Model),视图(View)和控制器(Controller)。其中模型可对应于观察者模式中的观察目标,而视图对应于观察者,控制器可充当两者之间的中介者。当模型层的数据发生改变时,视图层将自动改变其显示内容。
-
spring的事件驱动模型
-
5、策略模式
-
定义:
每一个封装算法的类我们都可以称之为一种策略(Strategy),为了保证这些策略在使用时具有一致性,一般会提供一个抽象的策略类来做规则的定义,而每种算法则对应于一个具体策略类
-
角色:
-
Context(环境类):环境类是使用算法的角色,它在解决某个问题(即实现某个方法)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。
-
Strategy(抽象策略类):它为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。
-
ConcreteStrategy(具体策略类):它实现了在抽象策略类中声明的算法,在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。
-
-
案例:
/** 电影票类:环境类 */ class MovieTicket { private double price; private Discount discount; //维持一个对抽象折扣类的引用 public void setPrice(double price) { this.price = price; } //注入一个折扣类对象 public void setDiscount(Discount discount) { this.discount = discount; } public double getPrice() { //调用折扣类的折扣价计算方法 return discount.calculate(this.price); } } /** 折扣类:抽象策略类 */ interface Discount { public double calculate(double price); } /** 学生票折扣类:具体策略类 */ class StudentDiscount implements Discount { public double calculate(double price) { System.out.println("学生票:"); return price * 0.8; } } /** 儿童票折扣类:具体策略类 */ class ChildrenDiscount implements Discount { public double calculate(double price) { System.out.println("儿童票:"); return price - 10; } } /** VIP会员票折扣类:具体策略类 */ class VIPDiscount implements Discount { public double calculate(double price) { System.out.println("VIP票:"); System.out.println("增加积分!"); return price * 0.5; } }
-
实现:
-
Spring中Bean的初始化
-
JDK中Comparator接口,该接口有一个compare方法,传递2个对象,进行比较。
-
6、模板方法模式
-
角色:
-
AbstractClass(抽象类):在抽象类中定义了一系列基本操作(PrimitiveOperations),这些基本操作可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中可以重定义或实现这些步骤。同时,在抽象类中实现了一个模板方法(Template Method),用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。
-
ConcreteClass(具体子类):它是抽象类的子类,用于实现在父类中声明的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。
-
-
应用:
-
RestTemplate: Http Restful接口请求模板
-
dbcTemplate: JDBC关系型数据库操作模板
-