设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
一、设计模式的分类
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
中美合作的故事——创建型模式提供国际环境,无战争,求发展;结构型模式为中美合作提供理由,即和平时代的互利共赢,行为型模式就具体到两个大国之间是如何合作,比如经济合作、文化合作等
二、设计模式的六大原则
1、开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。
里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。
LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
5、迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。
三、Java的23中设计模式
1、工厂方法模式(Factory Method)
就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建,有三种,都差不多,这里只写一种博主自己喜欢用的
public interface Sender {
public void Send();
}
public class MailSender implements Sender {
@Override
public void Send() {
System.out.println("this is mailsender!");
}
}
public class SmsSender implements Sender {
@Override
public void Send() {
System.out.println("this is sms sender!");
}
}
public class SendFactory {
public static Sender produceMail(){
return new MailSender();
}
public static Sender produceSms(){
return new SmsSender();
}
}
public class FactoryTest {
public static void main(String[] args) {
Sender sender = SendFactory.produceMail();
sender.Send();
}
}
2、抽象工厂模式(Abstract Factory)
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
类还是一样,工厂类进行改进一下。
public interface Provider {
public Sender produce();
}
public class SendMailFactory implements Provider {
@Override
public Sender produce(){
return new MailSender();
}
}
public class SendSmsFactory implements Provider{
@Override
public Sender produce() {
return new SmsSender();
}
}
发现区别了嘛,其实就是工厂类多了一层,多了个接口。
3、单例模式(Singleton)
单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。
单例模式有五种,1.饿汉式 2.懒汉式 3.双重检查锁 4.静态私有内部类 5.枚举。前面两种都不支持并发,后面三种都可以支持
//饿汉式
public class Singleton1 {
private Singleton1() {
}
private static Singleton1 instance = new Singleton1();
public static Singleton1 getInstance(){
return instance;
}
}
//懒汉式、不支持多并发
public class Singleton2 {
private Singleton2() {
}
private static Singleton2 instance = null;
public static Singleton2 getInstance(){
if (instance == null){
instance = new Singleton2();
}
return instance;
}
}
//double checked locking、支持多并发、效率高、添加volatile关键字
public class Singleton3 {
private Singleton3() {
}
private volatile static Singleton3 instance = null;
public static Singleton3 getInstance(){
if (instance == null){//1
synchronized (Singleton3.class) {
if (instance == null)//2
instance = new Singleton3();
}
}
return instance;
}
}
//静态私有内部类、支持多并发、效率高、
public class Singleton4 {
private Singleton4() {
}
private static class SingletonHolder{
private static Singleton4 instance = new Singleton4();
}
public static Singleton4 getInstance(){
return SingletonHolder.instance;
}
}
public enum Singleton5 {
//枚举元素本身就是单例
INSTANCE;
//添加自己需要的操作
public void singletonOperation(){
}
}
4、建造者模式(Builder)
工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和类的集合,也可以说是构建复杂的对象可以使用构造者模式。比如mybatis-plus的builder类
/**
* Builder.java
* 建造者
*/
abstract class Builder {
//汉堡
abstract Builder bulidA(String mes);
//饮料
abstract Builder bulidB(String mes);
//薯条
abstract Builder bulidC(String mes);
//甜品
abstract Builder bulidD(String mes);
//获取套餐
abstract Product build();
}
/**
* Product.java
* 产品(麦当劳套餐)
*/
public class Product {
private String buildA="汉堡";
private String buildB="饮料";
private String buildC="薯条";
private String buildD="甜品";
public String getBuildA() {
return buildA;
}
public void setBuildA(String buildA) {
this.buildA = buildA;
}
public String getBuildB() {
return buildB;
}
public void setBuildB(String buildB) {
this.buildB = buildB;
}
public String getBuildC() {
return buildC;
}
public void setBuildC(String buildC) {
this.buildC = buildC;
}
public String getBuildD() {
return buildD;
}
public void setBuildD(String buildD) {
this.buildD = buildD;
}
@Override
public String toString() {
return buildA+"\n"+buildB+"\n"+buildC+"\n"+buildD+"\n"+"组成套餐";
}
}
/**
* ConcreteBuilder.java
* 具体建造者(服务员)
*/
public class ConcreteBuilder extends Builder{
private Product product;
public ConcreteBuilder() {
product = new Product();
}
@Override
Product build() {
return product;
}
@Override
Builder bulidA(String mes) {
product.setBuildA(mes);
return this;
}
@Override
Builder bulidB(String mes) {
product.setBuildB(mes);
return this;
}
@Override
Builder bulidC(String mes) {
product.setBuildC(mes);
return this;
}
@Override
Builder bulidD(String mes) {
product.setBuildD(mes);
return this;
}
}
/**
* Test.java
* 测试类
*/
public class Test {
public static void main(String[] args) {
ConcreteBuilder concreteBuilder = new ConcreteBuilder();
Product build = concreteBuilder
.bulidA("牛肉煲")
.bulidC("全家桶")
.bulidD("冰淇淋")
.build();
System.out.println(build.toString());
}
}
这里这只是一种,还有比如创建一个牛肉堡类集合,这也是建造者模式。总之就是创建复杂对象就是建造者模式,直接new一个对象返回就是抽象工厂模式
5、原型模式(Prototype)
原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。克隆出来的对象是属性和原来对象一样,地址值不一样。然后clone有浅拷贝和深拷贝,深拷贝就是连对象里面的对象都复制,而浅拷贝只拷非对象属性。
public class Prototype implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private String string;
private SerializableObject obj;
/* 浅复制 */
public Object clone() throws CloneNotSupportedException {
Prototype proto = (Prototype) super.clone();
return proto;
}
/* 深复制 */
public Object deepClone() throws IOException, ClassNotFoundException {
/* 写入当前对象的二进制流 */
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
/* 读出二进制流产生的新对象 */
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
public SerializableObject getObj() {
return obj;
}
public void setObj(SerializableObject obj) {
this.obj = obj;
}
}
class SerializableObject implements Serializable {
private static final long serialVersionUID = 1L;
}
6.适配器模式
三种适配器模式:
类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。
接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。
//类的适配器模式
public class Source {
public void method1() {
System.out.println("this is original method!");
}
}
public interface Targetable {
/* 与原类中的方法相同 */
public void method1();
/* 新类的方法 */
public void method2();
}
public class Adapter extends Source implements Targetable {
@Override
public void method2() {
System.out.println("this is the targetable method!");
}
}
public class AdapterTest {
public static void main(String[] args) {
Targetable target = new Adapter();
target.method1();
target.method2();
}
}
//对象的适配器模式
public class Wrapper implements Targetable {
private Source source;
public Wrapper(Source source){
super();
this.source = source;
}
@Override
public void method2() {
System.out.println("this is the targetable method!");
}
@Override
public void method1() {
source.method1();
}
}
public class AdapterTest {
public static void main(String[] args) {
Source source = new Source();
Targetable target = new Wrapper(source);
target.method1();
target.method2();
}
}
//接口的适配器模式
public interface Sourceable {
public void method1();
public void method2();
}
public abstract class Wrapper2 implements Sourceable{
public void method1(){}
public void method2(){}
}
public class SourceSub1 extends Wrapper2 {
public void method1(){
System.out.println("the sourceable interface's first Sub1!");
}
}
public class SourceSub2 extends Wrapper2 {
public void method2(){
System.out.println("the sourceable interface's second Sub2!");
}
}
public class WrapperTest {
public static void main(String[] args) {
Sourceable source1 = new SourceSub1();
Sourceable source2 = new SourceSub2();
source1.method1();
source1.method2();
source2.method1();
source2.method2();
}
}
7、装饰模式(Decorator)
装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例
//资源类接口
public interface Sourceable {
public void method();
}
//资源类实现
public class Source implements Sourceable {
@Override
public void method() {
System.out.println("the original method!");
}
}
//装饰类
public class Decorator implements Sourceable {
//持有资源类
private Sourceable source;
public Decorator(Sourceable source){
super();
this.source = source;
}
@Override
public void method() {
System.out.println("before decorator!");
source.method();
System.out.println("after decorator!");
}
}
//测试类
public class DecoratorTest {
public static void main(String[] args) {
Sourceable source = new Source();
Sourceable obj = new Decorator(source);
obj.method();
}
}
8、代理模式(Proxy)
代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思
//资源类接口
public interface Sourceable {
public void method();
}
//资源实现类
public class Source implements Sourceable {
@Override
public void method() {
System.out.println("the original method!");
}
}
//代理类
public class Proxy implements Sourceable {
private Source source;
//持有资源类并实例化
public Proxy(){
super();
this.source = new Source();
}
@Override
public void method() {
before();
source.method();
atfer();
}
private void atfer() {
System.out.println("after proxy!");
}
private void before() {
System.out.println("before proxy!");
}
}
//测试类
public class ProxyTest {
public static void main(String[] args) {
Sourceable source = new Proxy();
source.method();
}
}
装饰模式和代理模式有什么区别?其实很简单,装饰模式是透明的,也就是你需要传入需要装饰的类,而代理模式是不透明的,你看不到被代理的类的实例化。拿装修好的房子来举例,装饰模式是你买了一个毛坯房给装饰者装修,然后还给你一个装修好的房子。而代理模式则是直接买了精装修的房子,至于没装修之前是什么样,你不知道。
9、外观模式(Facade)
外观模式是为了解决类与类之间的依赖关系的,外观模式不涉及接口。
//cpu
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!");
}
}
//电脑有cpu,内存,磁盘等等组件,开启电脑时,你是没有感知的,你只有一个动作,开启,实际上是每个组件都会去逐一开启
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 User {
public static void main(String[] args) {
Computer computer = new Computer();
computer.startup();
computer.shutdown();
}
}
10、桥接模式(Bridge)
桥接模式就是把事物和其具体实现分开,使他们可以各自独立的变化。其实就是通过桥接实现分离,从而达到目的。
//资源类接口
public interface Sourceable {
public void method();
}
//两个实现
public class SourceSub1 implements Sourceable {
@Override
public void method() {
System.out.println("this is the first sub!");
}
}
public class SourceSub2 implements Sourceable {
@Override
public void method() {
System.out.println("this is the second sub!");
}
}
//定义一个桥,持有Sourceable的一个实例
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();
}
}
这里桥接模式又是持有实例,然后调用实例的方法。他和装饰模式很像,区别在于装饰模式是需要实现资源类接口,所以就是资源类所有的方法他都直接拥有,而桥接模式不一样,他只是只持有资源类接口,想用才用。
桥接模式和适配器模式也有些像,桥接模式是可以扩展和修改桥接中的类,但是不能改变接口,而适配器模式则是可以改变接口实现适配的(接口的适配器模式很明显)。
11、组合模式(Composite)
组合模式有时又叫部分-整体模式在处理类似树形结构的问题时比较方便。将多个对象组合在一起进行操作,常用于表示树形结构中,例如二叉树,数等
//树节点
public class TreeNode {
private String name;
//父节点
private TreeNode parent;
//子节点
private Vector<TreeNode> children = new Vector<TreeNode>();
public TreeNode(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public TreeNode getParent() {
return parent;
}
public void setParent(TreeNode parent) {
this.parent = parent;
}
//添加孩子节点
public void add(TreeNode node){
children.add(node);
}
//删除孩子节点
public void remove(TreeNode node){
children.remove(node);
}
//取得孩子节点
public Enumeration<TreeNode> getChildren(){
return children.elements();
}
}
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");
//节点B
TreeNode nodeB = new TreeNode("B");
//节点C
TreeNode nodeC = new TreeNode("C");
//节点B添加节点C为子节点
nodeB.add(nodeC);
//树添加数节点B 最后的结构就是树->节点B->节点C
tree.root.add(nodeB);
System.out.println("build the tree finished!");
}
}
12、享元模式(Flyweight)
享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,
通常和工厂模式一起使用。
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;
}
}
}
13、策略模式(strategy)
策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。
//统一接口
public interface ICalculator {
public int calculate(String exp);
}
//辅助类:
public abstract class AbstractCalculator {
public int[] split(String exp,String opt){
String array[] = exp.split(opt);
int arrayInt[] = new int[2];
arrayInt[0] = Integer.parseInt(array[0]);
arrayInt[1] = Integer.parseInt(array[1]);
return arrayInt;
}
}
//三个实现类
public class Plus extends AbstractCalculator implements ICalculator {
@Override
public int calculate(String exp) {
int arrayInt[] = split(exp,"\\+");
return arrayInt[0]+arrayInt[1];
}
}
public class Minus extends AbstractCalculator implements ICalculator {
@Override
public int calculate(String exp) {
int arrayInt[] = split(exp,"-");
return arrayInt[0]-arrayInt[1];
}
}
public class Multiply extends AbstractCalculator implements ICalculator {
@Override
public int calculate(String exp) {
int arrayInt[] = split(exp,"\\*");
return arrayInt[0]*arrayInt[1];
}
}
//测试类
public class StrategyTest {
public static void main(String[] args) {
String exp = "2+8";
ICalculator cal = new Plus();
int result = cal.calculate(exp);
System.out.println(result);
}
}
这里总结一下相似的几个模式区别:
代理模式:实现资源类接口,内部实例化资源类,调用资源类方法,目标方法是稳定不可变的。
装饰模式:实现资源类接口,内部不实例化资源类,需要使用者传入,调用资源类方法,目标方法是稳定不可变的。
适配器模式:继承资源类实现新的接口或者实现适配器类(持有资源类实例),可以添加一些新的方法,老方法也可以修改。目标方法可以是不稳定可变的(可沿用或者另起)。
桥接模式:实现桥接抽象类,桥接抽象类持有资源类实例,可以添加一些新方法,老方法不可以修改。目标方法是稳定不可变的。
策略模式:需要指定资源类,然后一系列操作得出运算结果。目标方法是自定义的。
14、模板方法模式(Template Method)
一个抽象类中,有一个主方法,再定义1…n个方法,可以是抽象的,也可以是实际的方法,定义一个类,继承该抽象类,重写抽象方法,通过调用抽象类,实现对子类的调用。
public abstract class AbstractCalculator {
/*主方法,实现对本类其它方法的调用*/
public final int calculate(String exp,String opt){
int array[] = split(exp,opt);
return calculate(array[0],array[1]);
}
/*被子类重写的方法*/
abstract public int calculate(int num1,int num2);
public int[] split(String exp,String opt){
String array[] = exp.split(opt);
int arrayInt[] = new int[2];
arrayInt[0] = Integer.parseInt(array[0]);
arrayInt[1] = Integer.parseInt(array[1]);
return arrayInt;
}
}
public class Plus extends AbstractCalculator {
@Override
public int calculate(int num1,int num2) {
return num1 + num2;
}
}
public class StrategyTest {
public static void main(String[] args) {
String exp = "8+8";
AbstractCalculator cal = new Plus();
int result = cal.calculate(exp, "\\+");
System.out.println(result);
}
}
15、观察者模式(Observer)
观察者模式很好理解,类似于邮件订阅和RSS订阅,当我们浏览一些博客或wiki时,经常会看到RSS图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。
//观察者接口
public interface Observer {
public void update();
}
//观察者1
public class Observer1 implements Observer {
@Override
public void update() {
System.out.println("observer1 has received!");
}
}
//观察者2
public class Observer2 implements Observer {
@Override
public void update() {
System.out.println("observer2 has received!");
}
}
//主题接口
public interface Subject {
/*增加观察者*/
public void add(Observer observer);
/*删除观察者*/
public void del(Observer observer);
/*通知所有的观察者*/
public void notifyObservers();
/*自身的操作*/
public void operation();
}
//主题抽象类
public abstract class AbstractSubject implements Subject {
//观察者集合
private Vector<Observer> vector = new Vector<Observer>();
//添加观察者
@Override
public void add(Observer observer) {
vector.add(observer);
}
//删除观察者
@Override
public void del(Observer observer) {
vector.remove(observer);
}
//通知到每个人
@Override
public void notifyObservers() {
Enumeration<Observer> enumo = vector.elements();
while(enumo.hasMoreElements()){
enumo.nextElement().update();
}
}
}
//我的主题
public class MySubject extends AbstractSubject {
//主题更新
@Override
public void operation() {
System.out.println("update self!");
//调用通知
notifyObservers();
}
}
public class ObserverTest {
public static void main(String[] args) {
Subject sub = new MySubject();
sub.add(new Observer1());
sub.add(new Observer2());
sub.operation();
}
}
16、迭代器模式(Iterator)
迭代器模式就是顺序访问聚集中的对象,一般来说,集合中非常常见,如果对集合类比较熟悉的话,理解本模式会十分轻松。集合里面有迭代器,迭代器里面又会有集合这个对象(实例化迭代器时会传入this这个集合对象)。
public interface Collection {
public Iterator iterator();
/*取得集合元素*/
public Object get(int i);
/*取得集合大小*/
public int size();
}
public interface Iterator {
//前移
public Object previous();
//后移
public Object next();
public boolean hasNext();
//取得第一个元素
public Object first();
}
public class MyCollection implements Collection {
public String string[] = {"A","B","C","D","E"};
@Override
public Iterator iterator() {
return new MyIterator(this);
}
@Override
public Object get(int i) {
return string[i];
}
@Override
public int size() {
return string.length;
}
}
public class MyIterator implements Iterator {
private Collection collection;
private int pos = -1;
public MyIterator(Collection collection){
this.collection = collection;
}
@Override
public Object previous() {
if(pos > 0){
pos--;
}
return collection.get(pos);
}
@Override
public Object next() {
if(pos<collection.size()-1){
pos++;
}
return collection.get(pos);
}
@Override
public boolean hasNext() {
if(pos<collection.size()-1){
return true;
}else{
return false;
}
}
@Override
public Object first() {
pos = 0;
return collection.get(pos);
}
}
public class Test {
public static void main(String[] args) {
Collection collection = new MyCollection();
Iterator it = collection.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
17、责任链模式(Chain of Responsibility)
有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。但是发出者并不清楚到底最终那个对象会处理该请求,所以,责任链模式可以实现,在隐瞒客户端的情况下,对系统进行动态的调整。
public interface Handler {
public void operator();
}
public abstract class AbstractHandler {
private Handler handler;
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
}
public class MyHandler extends AbstractHandler implements Handler {
private String name;
public MyHandler(String name) {
this.name = name;
}
@Override
public void operator() {
System.out.println(name+"deal!");
if(getHandler()!=null){
getHandler().operator();
}
}
}
public class Test {
//简单理解就是handler里面有handler,嵌套了几个
public static void main(String[] args) {
MyHandler h1 = new MyHandler("h1");
MyHandler h2 = new MyHandler("h2");
MyHandler h3 = new MyHandler("h3");
h1.setHandler(h2);
h2.setHandler(h3);
h1.operator();
}
}
这里说一下组合模式和责任链模式的区别
组合模式:对象拥有对象(对象是同一类型)
责任链模式:对象拥有对象(对象是同一类型),且外部调用某个方法时,所有对象都要循环调用完。
18、命令模式(Command)
命令模式很好理解,举个例子,司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,口令经过传递,传到了士兵耳朵里,士兵去执行。这个过程好在,三者相互解耦,任何一方都不用去依赖其他人,只需要做好自己的事儿就行,司令员要的是结果,不会去关注到底士兵是怎么实现的。
//命令接口
public interface Command {
public void exe();
}
//命令
public class MyCommand implements Command {
//接受者
private Receiver receiver;
public MyCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void exe() {
receiver.action();
}
}
//接受者
public class Receiver {
public void action(){
System.out.println("command received!");
}
}
//发号施令者
public class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void action(){
command.exe();
}
}
public class Test {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command cmd = new MyCommand(receiver);
Invoker invoker = new Invoker(cmd);
invoker.action();
}
}
19、备忘录模式(Memento)
主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象。
//原始类
public class Original {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Original(String value) {
this.value = value;
}
public Memento createMemento(){
return new Memento(value);
}
public void restoreMemento(Memento memento){
this.value = memento.getValue();
}
}
//备忘录类
public class Memento {
private String value;
public Memento(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
//保存备忘录的类
public class Storage {
private Memento memento;
public Storage(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
public class Test {
public static void main(String[] args) {
// 创建原始类
Original origi = new Original("egg");
// 创建备忘录
Storage storage = new Storage(origi.createMemento());
// 修改原始类的状态
System.out.println("初始化状态为:" + origi.getValue());
origi.setValue("niu");
System.out.println("修改后的状态为:" + origi.getValue());
// 回复原始类的状态
origi.restoreMemento(storage.getMemento());
System.out.println("恢复后的状态为:" + origi.getValue());
}
}
20、状态模式(State)
当对象的状态改变时,同时改变其行为。
//状态
public class State {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public void method1(){
System.out.println("execute the first opt!");
}
public void method2(){
System.out.println("execute the second opt!");
}
}
package com.xtfggef.dp.state;
//状态模式的切换类
public class Context {
private State state;
public Context(State state) {
this.state = state;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void method() {
if (state.getValue().equals("state1")) {
state.method1();
} else if (state.getValue().equals("state2")) {
state.method2();
}
}
}
public class Test {
public static void main(String[] args) {
State state = new State();
Context context = new Context(state);
//设置第一种状态
state.setValue("state1");
context.method();
//设置第二种状态
state.setValue("state2");
context.method();
}
}
21、访问者模式(Visitor)
访问者模式就是一种分离对象数据结构与行为的方法,通过这种分离,可达到为一个被访问者动态添加新的操作而无需做其它的修改的效果。访问者访问被访问者,被访问者调用访问者参观方法并传入自身,访问者调用被访问者方法。下面案例( A.accept(B)->B.visit(A)->A.getSubject() )
//访问者接口
public interface Visitor {
public void visit(Subject sub);
}
public class MyVisitor implements Visitor {
@Override
public void visit(Subject sub) {
System.out.println("visit the subject:"+sub.getSubject());
}
}
//被访问者接口
public interface Subject {
public void accept(Visitor visitor);
public String getSubject();
}
public class MySubject implements Subject {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String getSubject() {
return "love";
}
}
public class Test {
public static void main(String[] args) {
Visitor visitor = new MyVisitor();
Subject sub = new MySubject();
sub.accept(visitor);
}
}
22、中介者模式(Mediator)
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
//中介者接口
public interface Mediator {
public void createMediator();
public void workAll();
}
//中介者
public class MyMediator implements Mediator {
private User user1;
private User user2;
public User getUser1() {
return user1;
}
public User getUser2() {
return user2;
}
@Override
public void createMediator() {
user1 = new User1(this);
user2 = new User2(this);
}
@Override
public void workAll() {
user1.work();
user2.work();
}
}
//被中介的抽象接口
public abstract class User {
private Mediator mediator;
public Mediator getMediator(){
return mediator;
}
public User(Mediator mediator) {
this.mediator = mediator;
}
public abstract void work();
}
//被中介者1
public class User1 extends User {
public User1(Mediator mediator){
super(mediator);
}
@Override
public void work() {
System.out.println("user1 exe!");
}
}
//被中介者2
public class User2 extends User {
public User2(Mediator mediator){
super(mediator);
}
@Override
public void work() {
System.out.println("user2 exe!");
}
}
public class Test {
public static void main(String[] args) {
Mediator mediator = new MyMediator();
mediator.createMediator();
mediator.workAll();
}
}
23、解释器模式(Interpreter)
解释器模式是指给定一个使用规定格式和语法的语言,并且建立一个解释器来解释该语言中的句子。解释器本身就是一种按照规定的语法进行解析的方案,但是总体来说也是一种使用频率相对较低但学习难度较大的设计模式。解释器模式用来做各种各样的解释器,如正则表达式等的解释器等等。
public interface Expression {
public int interpret(Context context);
}
public class Plus implements Expression {
@Override
public int interpret(Context context) {
return context.getNum1()+context.getNum2();
}
}
public class Minus implements Expression {
@Override
public int interpret(Context context) {
return context.getNum1()-context.getNum2();
}
}
public class Context {
private int num1;
private int num2;
public Context(int num1, int num2) {
this.num1 = num1;
this.num2 = num2;
}
public int getNum1() {
return num1;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
}
public class Test {
public static void main(String[] args) {
// 计算9+2-8的值
int result = new Minus().interpret((new Context(new Plus()
.interpret(new Context(9, 2)), 8)));
System.out.println(result);
}
}
在spring中的应用
工厂方法模式:AbstractBeanFactory 类的 getBean 方法,可以理解为简单工厂,根据不同参数获取不同的 bean 对象。
抽象工厂模式:在 Spring 中,BeanFactory 是用于管理 Bean 的一个工厂,所有工厂都是 BeanFactory 的子类。这样我们可以通过 IOC 容器来管理访问 Bean,根据不同的策略调用 getBean() 方法,从而获得具体对象。
单例模式:Spring中创建单例的过程真的是非常的绕,但是逻辑还是非常清楚的,就是将我们需要的对象放在map中,下次需要的时候就直接从map中获取,这里会判断是原型还是单例。
建造者模式:spring框架,主要是用来管理对象,创建一个对象是极其复杂的,建造者模式在解析xml文件,创建BeanDefiniton中发挥很大的作用。
原型模式:在创建ioc容器后,通过getBean()获取bean对象时,往里追可以发现在核心方法处spring对bean的scope属性进行了判断,配置了prototype时,进入了原型模式的使用。spring 中 org.springframework.beans.BeanUtils 的 copyProperties 方法复制一个对象的属性到另一个对象。
适配器模式:spring AOP中的MethodBeforeAdviceAdapter类把Advice适配为MethodInterceptor对象;slf4j 为了能适配其他日志框架,提供了各种适配库。 比如为了适配 log4j,在 slf4j-log4j.jar 包中提供 org.slf4j.impl.Log4jLoggerAdapter 记录日志的适配类,Log4jLoggerAdapter 继承自 org.slf4j.spi.LocationAwareLogger 继承自 org.slf4j.Logger。 Log4jLoggerAdapter 持有了 org.apache.log4j.Logger 对象,完成了用该 log4j 的日志对象实现 slf4j 的日志接口中方法的适配。
装饰模式:JDK 中的 java.io 包下,InputStream、OuputStream、Reader、Writer 及它们的子类。BufferedInputStream、DataInputStream 都继承自 FilterInputStream,FilterInputStream 对 InputStream 进行了公共实现,避免 BufferedInputStream、DataInputStream 都各自进行相同的实现。在 Spring 中,TransactionAwareCacheDecorator 类相当于装饰器模式中的抽象装饰角色,主要用来处理事务缓存。
代理模式:spring中代理有两种,Jdk代理方式和CGLIB。
外观模式:Tomcat 中,catalina.jar 中的 RequestFacade 和 ResponseFacade 两个类就使用了外观模式,Request、Response 偏底层,且交互复杂,Facade 隐藏了 Request 和 Response 的底层实现细节,降低了底层方法被调用出错的风险。比如spring Dao层就是外观模式。
桥接模式:JDBC Driver作为抽象桥类,而驱动包如com.mysql.jdbc.Driver具体的实现桥接类,而Connection是被桥接的对象
组合模式:CompositeCacheManager,Mybatis 在处理 xml 动态 sql 中用到了组合模式,SqlNode 的实现类通过容器类与叶子节点构造成树形结构,使用 apply 动态解析出完整的 SQL
享元模式:String常量池, Integer 的静态内部类 IntegerCache,在未设置 java.lang.Integer.IntegerCache.high 时,JVM 加载 IntegerCache 类时,静态方法块缓存了 -128 ~ 127;设置了 high 最大值取 127 与 high 中的较大者。
策略模式:Spring中代理对象的创建使用了策略模式。抽象策略是AopProxy接口,Cglib2AopProxy和JdkDynamicAopProxy分别代表两种策略的实现方式,ProxyFactoryBean就是代表Context角色,它根据条件选择使用Jdk代理方式还是CGLIB方式。
模板方法模式:JdbcTemplate实现了一系列常用的数据访问的算法骨架。
观察者模式: ApplicationListener, ContextLoaderListener等。
迭代器模式:集合。
责任链模式:handler,filter,Intercept。
命令模式:Tomcat 中命令模式在 Connector 和 Container 组件之间有体现,Tomcat 作为一个应用服务器,无疑会接受到很多请求。 Connector 作为抽象请求者,HttpConnector 作为具体请求者。HttpProcessor 作为命令。Container 作为命令的抽象接受者,ContainerBase 作为具体的接受者。客户端就是应用服务器 Server 组件了。JDK 中的 Runnable 接口,Runnable 相当于命令模式中的抽象命令角色。Runnable 中的 run() 方法就当于 execute() 方法。
备忘录模式:spring-webflow 中的stateManageableMessageContext.createMessageMemento()
状态模式:spring-statemachine spring状态机
访问者模式:Spring 中的 BeanDefinitionVisitor 类主要用于访问 BeanDefinition
中介者模式:Java web 开发中 MVC 模式(Model-View-Controller)就用到了中介者模式,Controller 就是 Model 和 View 的中介
解释器模式:在 Spring 中,ExpressionParser 接口内部采用的是解释器模式