设计模式介绍
-
设计模式(Design Patterns):
- 一套被 重复应用, 少数人通晓, 通过分类编目, 代码设计 的总结
- 应用设计模式是为了可重用代码, 让代码更容易了解, 保障代码可靠性
- 我的项目中正当使用设计模式能够完满的解决很多问题, 每种模式都有相应的原理与之对应,
-
每个模式形容了一个在咱们四周一直反复产生的问题, 以及该问题的外围解决方案
# 设计模式分类- 总体来说, 设计模式分为三大类:
-
创立型模式(5 种):
- 工厂办法模式
- 形象工厂模式
- 单例模式
- 建造者模式
- 原型模式
-
结构型模式(7 种):
- 适配器模式
- 装璜器模式
- 代理模式
- 外观模式
- 桥接模式
- 组合模式
- 享元模式
-
行为型模式(11 种):
- 策略模式
- 模板办法模式
- 观察者模式
- 迭代子模式
- 责任链模式
- 命令模式
- 备忘录模式
- 状态模式
- 访问者模式
- 中介者模式
- 解释器模式
-
其余两类模式:
- 并发型模式
-
线程池模式
设计模式六大准则
繁多职责准则(Single Responsibility Principle) – 这里的设计模式准则, 次要探讨的是 Java 面向对象编程设计中设计准则, 繁多职责准则因为其实用的普遍性, 集体认为不放在六大准则之中
- 繁多职责准则 : 一个类只负责一项职责
- 不能存在多于一个导致类变更的起因
- 繁多职责准则合乎 ” 高内聚, 低耦合 ” 的思维
- 繁多职责准则不只是面向对象编程思维所特有的, 只有是模块化的程序设计, 都实用繁多职责准则
开闭准则(Open Close Principle)
- 开闭准则 : 对扩大凋谢, 对批改敞开
- 程序进行扩大的时候, 不能批改原有的代码, 实现一个热插拔的成果
- 为了使程序扩展性好, 易于保护和降级: 须要 应用接口和抽象类
里氏代换准则(Liskov Substitution Principle)
- 里氏代换准则 : 任何基类能够呈现的中央, 子类肯定能够呈现
- LSP 是 继承复用 的基石, 只有 当衍生类能够替换掉基类, 软件单位的性能不受影响时, 基类能力真正被复用, 衍生类也可能在基类的根底上减少新的行为
-
里氏代换准则是对实现抽象化的具体步骤的标准:
- 里氏代换准则是对开闭准则的补充
- 实现开闭准则的关键步骤就是抽象化
-
基类与子类的继承关系就是抽象化的具体实现
依赖倒转准则(Dependence Inversion Principle)
- 依赖倒转准则 : 针对接口编程, 依赖于形象而不依赖于具体
-
依赖倒转准则是开闭准则的根底
接口隔离准则(Interface Segregation Principle)
- 接口隔离准则 : 应用多个隔离的接口, 比应用单个接口要好, 升高类之间的耦合度
- 从接口隔离准则能够看出: 设计模式就是一个软件的设计思维
-
从大型软件架构登程, 为了降级和保护不便 : 升高依赖, 升高耦合
迪米特法令(起码晓得准则)(Demeter Principle)
-
迪米特法令: 起码晓得准则 , 一个实体该当尽量少的与其它实体产生相互作用, 使得功能模块互相独立
合成复用准则(Composite Reuse Principle)
-
合成复用准则 : 尽量应用合成或者聚合的形式, 而不是应用继承
Java 中 23 种设计模式
创立型模式
工厂办法模式(Factory Method)
工厂办法模式分为三种 : 一般工厂模式, 多个工厂办法模式, 动态工厂办法模式
一般工厂模式
-
建设一个工厂类, 对实现了同一接口的一些类进行实例的创立:
- 接口
public interface Sender{
public void Send();
} -
实现类
public class MailSender implements Sender{
@Override
public void Send(){System.out.println("MailSender Method");
}
}
public class SmsSender implements Sender{
@Override
public void Send(){System.out.println("SmsSender Method");
}
} -
工厂类
public class SendFactory{
public Sender produce(String type){if("mail".equals(type)){return new MailSender(); }else if("sms".equals(type)){return new SmsSender(); }else{System.out.println("Please input right type!"); }
}
} -
测试类
public class FactoryTest{
public static void main(String[] args){SendFactory factory=new SendFactory(); Sender sender=factory.produce("sms"); sender.Send();
}
} - 多个工厂办法模式是对一般工厂办法模式的改良
- 一般工厂办法模式中, 如果传递的字符串出错, 则不能创建对象
-
多个工厂办法模式提供多个工厂办法, 别离创建对象
-
SendFactory 类
public class SendFactory{public Sender produceMail(){return new MailSender(); } public Sender produceSms(){return new SmsSender(); }
}
-
测试类
public class FactoryTest{public static void main(String[] args){SendFactory factory=new SendFactory(); Sender sender=factory.produceMail(); sender.Send();}
}
-
将 多个工厂办法模式 中的办法设置为 静态方法, 不须要创立实例 , 间接调用即可
-
SendFactory
public class SendFactory{public static Sender produceMail(){return new MailSender(); } public static Sender produceSms(){return new SmsSender(); }
}
-
FactoryTest
public class FActoryTest{public static void main(String[] args){Sender sender=SenderFactory.produceMail(); sender.Send();}
}
-
工厂模式适宜呈现大量的产品须要创立, 并且具备独特的接口, 能够通过工厂办法模式创立:
- 一般工厂模式: 如果传入字符串有误, 就不能创建对象
- 动态工厂办法模式 绝对于多个工厂办法模式 , 不须要实例化工厂类
-
大多数状况下, 采纳动态工厂办法模式
形象工厂模式(Abstract Factory)
- 工厂办法模式问题: 类的创立依赖工厂类. 如果想要扩大程序, 必须对工厂类进行批改, 这违反了闭包准则
-
形象工厂模式: 创立多个工厂类, 一旦须要减少新的性能, 间接减少工厂类就能够, 不须要批改之前的工厂类
-
Sender
public interface Sender{public void Sender();
}
-
两个实现类
-
MailSender
public class MailSender implements Sender {@Override public void Send(){System.out.println("This is MailSender!"); }
}
-
SmsSender
public class SmsSender implements Sender{@Override public void Send(){System.out.println("This is SmsSender!"); }
}
-
-
两个工厂类
-
工厂类接口:
public interface Provider{public Sender produce();
}
-
SendMailFactory
public class SendMailFactory implements Provider{@Override public Sender produce(){return new MailSender(); }
}
-
SendSmsFactory
public class SendSmsFactory implements Provider{@Override public Sender produce(){return new SmsSender(); }
}
-
-
Test
public class Test{public static void main(String[] args){Provider provider=new SendMailFactory(); Sender sender=provider.produce(); sender.Send();}
}
-
形象工厂模式的长处就是拓展性强:
-
如果须要减少一个性能, 例如: 发及时信息
- 只需做一个 实现类, 实现 Sender 接口
-
做一个 工厂类, 实现 Provider 接口
单例模式(Singleton)
-
- 单例模式 : 保障在一个 JVM 中, 一个单例对象只有一个实例存在
-
单例模式的长处:
- 某些类创立比拟繁琐, 对于一些大型对象, 能够缩小很大的零碎开销
- 省去了 new 操作符, 升高了零碎内存的应用频率, 加重 GC(Garbage Collection- 垃圾回收)压力
- 有些类比方交易所的外围交易引擎, 管制着交易流程, 如果该类能够创立多个, 零碎会齐全凌乱, 所有只有应用单例模式, 能力保障外围交易服务器独立管制整个流程
-
单例类
public class Singleton{/* 公有动态实例, 避免被援用, 赋值为 null, 目标是实现提早加载 */ private static Singleton instance=null; /* 公有构造方法, 避免被实例化 */ private Singleton(){} /* 动态工厂办法, 创立实例 */ public static Singleton getInstance(){if(instance==null){instance=new Singleton(); } return instance; } /* 如果该对象被用于序列化, 能够保障对象在序列化前后保持一致 */ public Object ReadResolve(){return instance;}
}
-
思考到多线程平安, 首先会想到对 getInstance 办法加 synchronized 关键字:
public static synchronized Singleton getInstance(){if(instance==null){instance=new Singleton(); } return instance; }
因为 synchronized 锁住的是这个对象, 这样的用法, 每次调用 getInstance(), 都要对对象上锁, 在性能上会有所降落.
-
只有在第一次创建对象的时候须要加锁, 之后就不须要了:
public static Singleton getInstance(){if(instance==null){synchronized(instance){if(instance==null){instance=new Singleton(); } } } return instance; }
这样仿佛解决了问题, 将 synchronized 关键字退出外部, 这样在调用的时候是不须要加锁的, 只有在 instance 为 null, 并创建对象的时候才须要的加锁, 性能失去了晋升, 然而这样的状况还是有问题的
-
存在这样的状况:
- 在 Java 中创建对象和赋值操作是离开进行的
- 即 instance=new Singleton()是分两步执行的
-
JVM 并不保障这两个操作的先后顺序:
- 有可能 JVM 会为新的 Singleton 实例调配空空间, 而后间接赋值给 instance 成员
-
而后再去初始化这个 Singleton 实例
- 这样就可能会出错
-
示例:
-
A,B 两个线程
- A,B 线程同时进入第一个 if 判断
- A 首先进入 synchronized 块, 因为 instance 为null, 执行instance=new Singleton()
- 因为 JVM 外部的优化机制 ,JVM先划出一些调配给 Singleton 的空白内存, 并赋值给 instance 成员, 此时还没有开始初始化这个实例, 而后 A 来到了 synchronized 块
- B 进入 synchronized, 因为 i nstance 此时不是 null, 因而它马上来到了synchronized 块并将后果返回给调用该办法的程序
- 此时 B 线程打算应用 Singleton 实例, 发现它还没有初始化, 于是产生谬误
-
-
代码须要进一步优化:
private static class SingletonFactory{private static Singleton instance=new Singleton(); } public static Singleton getInstance(){return SingletonFactory.instance;}
-
理论状况是:
- 单例模式应用外部类来保护单例的实现
- JVM 外部的机制可能保障当一个类被加载的时候, 这个类的加载过程是互斥的
- 当第一次调用 getInstance 时,JVM 可能保障 instance 只被创立一次, 并且会保障把赋值给 instance 的内存初始化结束
-
该办法也只会在第一次调用的时候采纳互斥机制, 能够完满解决低性能的问题
public class Singleton{ /* 公有构造方法, 避免被实例化 */ private Singleton(){} /* 应用外部类保护单例 */ private static class SingletonFactory{private static Singleton instance=new Singleton(); } /* 获取实例 */ public static Singleton getInstance(){return SingletonFactory.instance;} /* 如果该对象被序列化, 能够保障对象在序列化前后保持一致 */ public Object readResolve(){return getInstance(); } }
这种办法, 如果在构造函数中抛出异样, 实例将永远不会创立, 也会出错.
只能依据理论场景, 抉择最适宜利用场景的实现办法
-
因为只须要在创立类的时候进行同步, 所以只有将创立和 getInstance()离开, 独自为创立加 synchronized 关键字, 也是能够的:
public class SingletonTest{ private static SingletonTest instance=null; private SingletonTest(){} private static synchronized void syncInit(){if(instance==null){instance=new SingletonTest(); } } public static SingletonTest getInstance(){if(instance==null){syncInit(); } return instance; } }
-
采纳 “ 影子实例 ” 的办法为单例对象的属性 同步更新:
public class SingletonTest{ private static SingletonTest instance=null; private Vector properties=null; public Vector getProperties(){return properties;} private SingletonTest(){} private static synchronized void syncInit(){if(instance==null){instance=new SingletonTest(); } } public static SingletonTest getInstance(){if(intance==null){syncInit(); } return instance; } public void updateProperties(){SingletonTest shadow=new SingletonTest(); properties=shadow.getProperties();} }
-
单例模式的特点:
-
单例模式了解起来简略, 具体实现起来是有肯定难度的 \
- 同步
- 异步
-
synchronized 关键字锁定的是对象, 应用的时候要在失当的中央应用:
- 留神须要应用锁的对象和过程, 有时候不是整个对象及整个过程都须要锁
-
-
采纳类的静态方法, 能够实现单例模式的成果
-
类的静态方法和单例模式的区别:
-
动态类不能实现接口:
- 从类的角度说, 是能够的, 然而这样就会毁坏动态了
- 接口中不容许有 static 润饰的办法, 即便实现了也是非动态的
-
单例能够被提早启动:
- 动态类在第一次加载时初始化
- 单例提早加载, 是因为有些类比拟宏大, 提早加载有助于晋升性能
-
单例能够被继承:
- 单例中的办法能够被重写
- 动态类外部办法都是 static, 无奈重写
-
单例比拟灵便:
- 从实现上讲, 单例只是一个一般的 Java 类, 只有满足单例的根本要求, 能够得心应手地实现其它性能
- 动态类不行
-
-
单例模式外部能够就是用一个动态类实现
建造者模式(Builder)
-
- 工厂模式提供的是创立单个类的模式
-
建造者模式: 将各种产品集中起来进行治理, 用来创立复合对象
- 复合对象: 指某个类具备不同的属性
- 建造者模式就是形象工厂类模式和 Test 类联合起来失去的
-
代码实现: 一个 Sender 接口, 两个实现类 MailSender 和SmsSender
-
Builder
public class Builder{
private List<Sender> list=new ArrayList<Sender>();public void produceMailSender(int count){
for(int i=0;i<count;i++){list.add(new MailSender()); }
}
public void produceSmsSender(int count){
for(int i=0;i<count;i++){list.add(new SmsSender()); }
}
} -
测试类
public class Test{
public static void main(String[] args){Builder builder=new Builder(); builder.produceMailSender(10);
}
} - 建造者模式将很多性能集成到一个类里, 这个类就能够发明出比较复杂的模块
-
建造者模式和工厂模式的区别:
- 工厂模式关注的是创立单个产品
-
建造者模式关注的是创立合乎对象, 多个局部
原型模式(Prototype)
- 原型模式: 将一个对象作为原型, 进行复制, 克隆, 产生一个和原对象相似的新对象
- 原型模式尽管是创立型模式, 然而与工厂模式没有关系
-
在 Java 中, 复制对象是通过clone() 实现的
-
原型类
public class Prototype implements Cloneable{
public Object clone() throws CloneNotSupportedException{Prototype proto=(Prototype)super.clone(); return proto;
}
} - 一个原型类, 只须要实现 Cloneable 接口, 重写clone() 办法
- clone办法能够改写为任何名称, 因为 Cloneable 接口是个空接口, 能够任意定义实现类的办法名
-
重点是super.clone():
- super.clone() 办法调用的是 Object 的clone() 办法
- 在 Object 类中 ,clone() 办法时 native 的
-
对象的深复制和浅复制:
-
深复制:
- 将一个对象复制后, 不论是根本类型还是援用类型, 都是从新创立的
- 深复制会进行完全彻底的复制
-
浅复制:
-
将一个对象复制后, 根本数据类型的变量都会从新创立, 而援用类型指向的还是原对象的援用
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 clone() throws IOException,ClassNotFoundException{ /* 写出以后对象的二进制流 */ ByteArrayOutputStream bos=new ByteArrayOutputStream(); ObjectOutputStream oos=new ObjectOutputStream(bos); oos.writeObject(this); /* 读入二进制流产生的新对象 */ ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray()); OnjectInputStream 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;}
-
-
-
要实现深复制:
- 要采纳 流的模式 读入以后对象的二进制输出
-
再写出二进制数据对应的对象
结构型模式
适配器模式(Adapter Pattern)
- 对象的适配器模式 是各种结构型模式的起源
- 适配器模式: 将某个类的接口转换成客户端冀望的另一个接口示意
- 目标: 打消因为接口不匹配所造成的类的兼容性问题
-
适配器模式次要分为三类:
- 类的适配器模式
- 对象的适配器模式
-
接口的适配器模式
类的适配器模式
-
核心思想: 有一个 Source 类, 领有一个办法待适配, 指标接口是 Targetable, 通过Adapter 类, 将 Source 的性能扩大到 Targetable 里
-
Source
public class Source{
public void method1(){System.out.println("This is original method!");
}
} -
Targetable
public interface Targetable{
/ 与原类中的办法雷同 /
public void method1();/ 新类办法 /
public void method2();
} -
Adapter
public class Adapter extends Source implemments Targetable{
@Override
public void method2(){System.out.println("This is the targetable method!");
}
} -
Adapter 类继承 Source 类, 实现 Targetable 接口:
-
AdapterTest
public class AdapterTest{
public static void main(String[] args){Targetable target=new Adapter(); target.method1(); target.method2();
}
} -
这样 Targetable 接口的实现类就具备 Source 类的性能
对象的适配器模式
-
基本思路和类的适配器雷同, 只是将 Adapter 类作批改 , 不继承 Source 类, 而是持有 Source 类的实例, 以达到解决兼容性问题
-
Wrapper
public class Wrapper implements Targetable{
private Source source;public Wrapper(Source source){
super(); this.source=source;
}
@Override
public void method1(){source.method1();
}
@override
public void method2(){System.out.println("This is the targetable method!");
}
} -
Test
public class AdapterTest{
public static void main(String[] args){Source source=new Source(); Targetable target=new Wrapper(source); target.method1(); target.nethod2();
}
} - 一个接口中有多个形象办法, 当写该接口的实现类时, 必须实现该接口的所有办法, 这样显著比拟节约, 因为并不是所有的办法都是须要用到的, 有时只有引入一些即可. 为了解决这样的问题, 引入了接口适配器模式
- 接口适配器模式: 借助于一个抽象类, 该抽象类实现了该接口以及所有的办法, 只须要和该抽象类进行分割即可.
-
只须要写一个类, 继承该抽象类, 重写须要用到的办法
- Sourceable
public interface Sourceable{
public void method1();
public void method2();
} -
Wrapper- 抽象类
public abstract class Wrapper implements Sourceable{
public void method1(){}public void method2(){}
} -
SourceSub1
public class SourceSub1 extends Wrapper{
public void method1(){System.out.println("The sourceable interface's first Sub");
}
} -
SourceSub2
public class SourceSub2 extends Wrapper(){
public void method2(){System.out.println("The Sourceable interface's second Sub");
}
} -
WrapperTest
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();
}
} -
三种适配器模式的利用场景:
-
类的适配器模式:
- 当心愿一个类转换成满足另一个新接口的类时, 能够应用类的适配器模式
- 创立一个新类, 继承原有的类, 实现新的接口即可
-
对象的适配器模式:
- 当心愿一个对象转换成满足另一个新接口的对象时, 能够应用对象的适配器模式
- 创立一个 Wrapper 类, 持有原类的一个实例, 在 Wrapper 类的办法中, 调用实例的办法即可
-
接口的适配器模式:
- 当不心愿实现一个接口中所有的办法时, 能够应用接口的适配器模式
-
创立一个抽象类 Wrapper, 实现所有办法, 写其它类时, 只有继承抽象类即可
装璜器模式(Decorator)
-
- 装璜器模式: 给一个对象动静地减少一些新的性能
- 装璜器模式要求装璜对象和被装璜对象 实现同一个接口, 装璜对象持有 被装璜对象的实例
-
Source类时被装璜类 ,Decorator类是装璜类, 能够为 Source 类动静地减少一些性能:
- Sourceable
public interface Sourceable{
public void method();
} -
Source
public class Source implements Sourceable{
@Override
public void method(){System.out.println("The original method!");
}
} -
Decorator
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!");
}
}-Test
public class DecoratorTest{
public static void main(String[] args){Sourceable source=new Source(); Sourceable obj=new Decorator(source); obj.method();
}
} -
装璜器模式利用场景:
- 须要扩大一个类的性能
- 动静地为一个对象减少性能, 而且还能动静地撤销(继承的性能是动态的, 不能动静增删)
-
装璜器模式的毛病: 产生过多相似的对象, 不易排错
代理模式(Proxy)
-
代理模式: 创立一个代理类, 替原对象进行一些操作
- Sourceable
public interface Sourceable{
public void method();
} -
Source
public class Source implements Sourceable{
@Override
public void method(){System.out.println("The original method!");
}
} -
Proxy
public class Proxy implements Sourceable{
private Source source;
public Proxy(){super(); this.source=new Source;
}
@Override
public void method(){before(); source.method(); after();
}
public void before(){
System.out.println("Before Proxy!");
}
public void after(){
System.out.println("After Proxy!");
}
} -
ProxyTest
public class ProxyTest{
public static void main(String[] args){Sourceable source=new Proxy(); source.method();
}
} -
代理模式的利用场景:
-
已有的办法在应用的时候须要对原有的办法进行改良, 有两种办法:
- 批改原有的办法来适应: 这样违反了 ” 对扩大凋谢, 对批改敞开 ” 的准则 . 不举荐应用
- 采纳一个代理类调用原有的办法, 且对产生的后果进行管制. 即代理模式
-
-
应用代理模式, 能够将性能划分的更加清晰, 有助于前期保护
外观模式(Facade)
- 在 Spring 中, 能够将类与类之间的关系配置到配置文件中
-
外观模式: 为了解决类与类之间的依赖关系, 将类鱼雷之间的关系放到一个 Facade 类中, 升高类与类之间的耦合度, 该模式中没有波及到接口
-
CPU
public class CPU{
public void startup(){System.out.println("CPU startup!");
}
public void shutdown(){
System.out.println("CPU shutdown!");
}
} -
Memory
public class Memory{
public void startup(){System.out.println("Memory startup!");
}
public void shutdown(){
System.out.println("Memory shutdown!");
}
} -
Disk
public class Disk{
public void startup(){System.out.println("Disk startup!");
}
public void shutdown(){
System.out.println("Disk shutdown!");
}
} -
Computer
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 the computer finished!");
}
public void shutdown(){
System.out.println("Begin to close the computer!"); cpu.shutdown(); memory.shutdown(); disk.shutdown(); System.out.println("Computer closed!");
}
}-User
public class User{
public static void main(String[] args){Computer computer=new Computer(); computer.startup(); computer.shutdown();
}
} - 如果没有 Computer 类 ,CPU,Memory,Disk之间会相互持有实例, 产生关系, 这样会造成重大依赖
- 批改一个类, 可能会带来其它类的批改
-
有了 Computer 类, 各个类之间的关系就放在类 Computer 类里, 这样就起到 解耦 的作用
桥接模式(Bridge)
- 桥接模式: 将事物和具体实现离开, 二者能够各自独立的变动
-
将抽象化与实现化解耦, 使得二者能够独立变动:
-
JDBC 桥DriverManager:
- JDBC 连贯数据库的时候, 在各个数据库之间进行切换, 根本不须要改变太多的代码, 甚至一点不必改变
- 起因在于 JDBC 提供对立接口, 每个数据库提供各自实现, 用一个叫作数据库驱动的程序来桥接即可
-
- Sourceable
public interface Sourceable{
public void method();
} -
SourceSub1
public class SourceSub1 implements Sourceable{
@Override
public void method(){System.out.println("This is the first sub!");
}
} -
SourceSub2
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 getSource(Sourceable source){
this.source=source;
}
} -
MyBridge
public class MyBridge extends Bridge{
public void method(){getSource().method();
}
} -
BridgeTest
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();
}
} - 通过对 Bridge 类的调用, 实现了对接口 Sourceable 的实现类 SourceSub1 和 SourceSub2 的调用
-
示例: JDBC 连贯原理
组合模式(Composite)
-
组合模式: 局部 - 整体模式, 在解决相似树形构造的问题时比拟不便
-
TreeNode
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();
}
} -
Tree
public class Tree{
TreeNode root=null;public Tree(String name){
root=new TreeNode(name);
}
public void main(String[] args){
Tree tree=new Tree("A"); TreeNode nodeB=new TreeNode("B"); TreeNode nodeC=new TreeNode("C"); nodeB.add(nodeC); tree.root.add(nodeB); System.out.println("Build the tree finished!");
}
} -
组合模式应用场景:
- 将多个对象组合在一起进行操作
-
罕用于示意树形构造中: 二叉树
享元模式
- 享元模式: 次要目标是实现对象共享, 即共享池
- 当零碎中对象多的时候能够缩小内存的开销, 通常与工厂模式一起应用
-
FlyWeightFactory: 负责创立和治理享元单元
- 当一个客户端申请时, 工厂须要查看以后对象池中是否有符合条件的对象
- 如果有, 就返回曾经存在的对象
- 如果没有, 就创立一个新对象
- 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,user,password); pool.add(conn); }catch(ClassNotFoundException e){e.printStackTrace(); }catch(SQLEXception e){e.printStackTrace(); } } } /* 返回连贯到连接池 */ public sysnchronized void release(){pool.add(conn); } /* 返回连接池中的一个数据库 */ public syschronized Connection getConnection(){if(pool.size()>0){Connection conn=pool.get(0); pool.remove(conn); return conn; }else{return null;} } }
- 通过连接池的连贯, 实现数据库连贯的共享:
- 不须要每一次从新创立连贯, 节俭数据库从新创立的开销, 晋升了零碎系能
行为型模式
-
11 种行为模式的关系:
- 第一类: 通过父类与子类的关系进行实现
- 第二类: 通过两个类之间的关系进行实现
- 第三类: 通过类的状态进行实现
-
第四类: 通过两头类进行实现
策略模式(Strategy)
-
策略模式:
- 定义了一系列算法, 并将每个算法封装起来, 能够互相替换, 算法的变动不会影响到应用算法的用户
- 设计一个接口, 为一系列实现类提供对立的办法, 多个实现类实现该接口
- 设计一个抽象类(选用, 作为辅助类), 提供辅助函数
- ICalculator接口提供对立的办法
-
AbstractCalculator是形象辅助类, 提供辅助办法
- ICalculator
public interface ICalculator{
public int calculate(String exp);
} -
AbstractCalculator
public abstract class AbstractCalcuator{
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;
}
} -
Plus
public class Plus extends AbstractCalculator implements ICalculator{
@Override
public int calculate(String exp){int arrayInt[]=split(exp,"\\+"); return arrayInt[0]+arrayInt[1];
}
} -
Minus
public class Minus extends AbstractCalculator implements ICalculator{
@Override
public int calculate(String exp){int arrayInt[]=split(exp,"-"); return arrayInt[0]-arrayInt[1];
}
}
-
Multiply
public class Multiply extends AbstractCalculator implements ICalculator{
@Override
public int calculate(String exp){int arrayInt[]=split(exp,"\\*"); return arrayInt[0]*arrayInt[1];
}
} -
StrategyTest
public class StrategyTest{
public static void mian(String[] args){String exp="2+8"; ICalculator cal=new Plus(); int result=cal.calculate(exp); System.out.println(result);
}
} -
策略模式的决定权在于用户:
- 零碎自身提供不同算法的实现
- 新增或删除算法
- 对各种算法做封装
-
策略模式多用在算法决策零碎中, 内部用户只须要决定应用哪一个算法即可
模板办法模式(Template Method)
-
模板办法模式:
- 一个抽象类中, 定义一个主办法
- 再定义无数个办法, 能够是形象的, 也能够是理论的办法
- 定义一个子类, 继承抽象类, 重写抽象类中的办法
- 通过调用抽象类, 实现对子类的调用
- AbstractCalculator类中定义一个主办法calculate()
- calculate() 调用split() 等
- Plus和 Minus 别离继承 AbstractCalculator 类
- 通过对 AbstractCalculator 的调用实现对子类的调用
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; } }
-
Plus
public class Plus extends AbstractCalculator{
@Override
public int calculate(int num1,int num2){return num1+num2;
}
} -
StrategyTest
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);
}
} - 首先将 exp 和 ”\ \ +” 做参数, 调用 AbstractCalculator 类里的 calculate(String,String) 办法
- 在calculate(String,String) 里调用同类的split()
- 而后再调用calculate(int,int) 办法
- 从这个办法进入到子类中
-
执行完 return num1+num2 之后, 将值返回到 AbstractCalculator 类, 赋值给result, 打印进去
观察者模式(Observer)
- 观察者模式是类与类之间的关系, 不波及继承
-
观察者模式相似邮件订阅和 RSS 订阅:
- 当你订阅了该内容, 如果后续有更新, 会及时接管到告诉
- 观察者模式: 当一个对象变动时, 依赖该对象的对象都会接管到告诉, 并且随着变动. 对象之间是一对多的关系
- MySubject类是主对象
- Observer1和 Observer2 是依赖于 MySubject 的对象
- 当 MySubject 变动时 ,Observer1和 Observer2 必然变动
- AbstractSubject类中定义者须要监控的对象列表, 能够对这些对象进行批改: 减少或者删除被监控对象
-
当 MySubject 变动时 ,AbstractSubject类负责告诉在列表内存在的对象
- Observer
public interface Observer{
public void update();
} -
Observer1
public class Observer1 implements Observer{
@Override
public void update(){System.out.println("Observer1 has received!");
}
} -
Observer2
public class Observer2 implements Observer{
@Override
public void update(){System.out.println("Observer2 has received!");
}
} -
Subject
public interface Subject{
/ 减少观察者 /
public void add(Observer observer);/ 删除观察者 /
public void del(Observer observer);/ 告诉所有观察者 /
public void notifyObservers();/ 本身的操作 /
public void operation();
} -
AbstractSubject
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();}
}
} -
MySubject
public class MySubject extends AbstractSubject{
@Override
public void operation(){System.out.println("update self!"); notifyObservers();
}
} -
ObserverTest
public class ObserverTest{
public static void main(String[] args){Subject sub=new MySubject(); sub.add(new Observer1()); sub.add(new Observer2()); sub.operation();
}
} -
观察者模式依据关系图, 新建我的项目, 应用代码依照总体思路走一遍, 这样容易了解观察者模式的思维
迭代子模式(Iterator)
- 迭代子模式是类与类之间的关系, 不波及继承
-
迭代子模式: 程序拜访汇集中的对象. 蕴含两层意思:
- 汇集对象: 须要遍历的对象
- 迭代器对象: 用于对汇集对象进行遍历拜访
- MyCollection中定义了汇合的一些操作
-
MyIterator中定义了一系列迭代操作, 并且持有 Collection 实例
-
Collection
public interface Collection{
public Iterator iterator();/ 获得汇合元素 /
public Object get(int i);/ 获得汇合大小 /
public int size();
} -
Iterator
public interface Iterator{
// 前移
puublic Object previous();// 后移
public Object next();
public boolean hasNext();// 获得第一个元素
public Object first();
} -
MyCollection
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;
}
} -
MyIterator
public class MyIterator implements Iterator{
private Collection collection;
private int pos=-1;public MyIterator(Collection collection){
this.collection=collection;
}
@Override
pbulic 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 Object hasNext(){if(pos<collection.size()-1){return true;}else{return false;}
}
@Override
public Object first(){pos=0; return collection.get(pos);
}
}
-
Test
public class Test{
Collection collection=new MyCollection();
Iterator it=collection.iterator();whhile(it.hasNext()){
System.out.println(it.next());
}
} -
JDK 中各个类都是这些根本的汇合, 加上一些设计模式, 再加一些优化组合到一起的, 只有把握这些, 能够写出自定义的汇合类, 甚至框架
责任链模式(Chain of Responsibility)
- 类与类之间的关系, 不波及继承
-
责任链模式:
- 有多个对象, 每个对象持有对下一个对象的援用, 这样造成一条链, 直到某个对象决定解决该申请
- 申请收回者并不分明到底最终哪个对象会解决该申请
- 责任链模式能够实现 : 在瞒哄客户端的状况下, 对系统进行动静调整
- Abstracthandler类提供了 get 和set办法, 不便 MyHandler 类设置和批改援用对象
-
MyHandler类是外围, 实例化后生成一系列互相持有的对象, 形成一条链
- Handler
public interface Handler{
public void operator();
} -
AbstractHandler
public abstract class AbstractHandler{private Handler handler;
private Handler getHandler(){
return handler;
}
private void setHandler(Handler handler){
this.handler=handler;
}
} -
MyHandler
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();}
}
} -
Test
public class Test{
public static void main(String[] args){MyHandler h1=new MyHandler("h1"); MyHanlder h2=new MyHandler("h2"); MyHandler h3=new MyHandler("h3"); h1.setHandler(h2); h2.setHandler(h3); h1.operator();
}
} - 链接上的申请能够是一条链, 能够是一个树, 还能够是一个环
- 模式自身不受这个束缚, 须要自定义实现
-
在同一个时刻, 命令只容许由一个对象传给另一个对象, 不容许传给多个对象
命令模式(Command)
- 类与类之间的关系, 不波及继承
-
命令模式了解示例:
- 司令员的作用是: 收回口令
- 口令通过传递, 传到士兵耳中, 士兵去执行
- 这个过程好在: 司令, 口令, 士兵三者互相解藕
- 任何一方都不必去依赖其它方, 只须要做好本身的事即可
- 司令员要的是后果, 不会去关注士兵到底怎么实现的
- Invoker是调用者(司令员)
- Receiver是被调用者(士兵)
-
MyCommand是命令, 实现了 Command 接口, 持有接管对象
- Command
public interface Command{
public void exe();
} -
MyCommand
public class MyCommand implements Command{
private Receiver receiver;public MyCommand(Receiver receiver){
this.receiver=receiver;
}
@Override
public void exe(){receiver.action();
}
} -
Receiver
public class Receiver{
public void action(){System.out.println("Command Received!");
}
} -
Invoker
public class Invoker{
private Command command;public Invoker(Command command){
this.command=command;
}
public void action(){
command.exe();
}
} -
Test
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();
}
} - 命令模式的目标: 达到命令的收回者和执行者之间的解耦, 实现申请和执行离开
-
Struts 其实就是一种将申请和出现拆散的技术, 应用了命令模式的设计思维
备忘录模式(Memento)
- 备忘录模式 : 次要目标是保留一个对象的某个状态, 以便在适当的时候复原对象
-
备忘录模式了解:
- 假如有原始类 A,A 中有各种属性,A 能够决定须要备份的属性
- 备忘录类 B 用来存储 A 的一些外部状态
- 类 C 用来存储备忘录, 并且只能存储, 不能进行批改等操作
- Original类是原始类, 外面有须要保留的属性 value 及创立一个备忘录类, 用来保留 value 值
- Memento类是备忘录类
-
Storage类是存储备忘录的类, 持有 Memento 类的实例
-
Original
public class Original{
private String value;private String getValue(){
return value;
}
private 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();
}
} -
Memento
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;
}
} -
Storage
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;
}
} -
Test
public class Test{
public static void main(String[] args){// 创立原始类 Original original=new Original("egg"); // 创立备忘录 Storage storage=new Storage(original.createMemento()); // 批改原始类的状态 System.out.println("初始状态为:"+original.getValue()); original.setValue("bulk"); System.out.println("批改后的状态:"+original.getValue()); // 复原原始类的状态 original.restoreMemento(storage.getMemento()); System.out.println("复原后的状态为:"+original.getValue());
}
} -
新建原始类时 ,value被初始化为 egg, 后通过批改, 将value 值批改为bulk, 最初进行复原状态, 后果胜利复原
状态模式(State)
- 状态模式 : 当对象的状态扭转时, 同时扭转对象的行为
-
状态模式了解示例:
- QQ 有几种不同的状态: 在线, 隐身, 繁忙等
- 每个状态对应不同的操作, 而且好友也能看到相干的状态
-
状态模式包含两层含意:
- 能够通过扭转状态来取得不同的行为
- 对象状态的变动能够被发现
- State类是个状态类
-
Context类能够实现切换
-
State
public class State{
private String value;private String getValue(){
return value;
}
private 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!");
}
} -
Context
public class Context{
private State state;private Context(State state){
this.state=state;
}
public State getState(){
return state;
}
public void setState(){
this.state=state;
}
public void method(){
if(state.getValue().equals("state1")){state.method1(); }else if(state.getValue().equals("state2")){state.method2(); }
}
} -
Test
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();
}
} -
状态模式的利用场景非常宽泛: 在做网站的时候, 心愿依据对象的属性, 区别一些性能等, 比如说权限管制等等
访问者模式(Visitor)
- 访问者模式将数据结构和作用于构造上的操作解耦, 使得操作汇合能够绝对自在地进行演变
-
访问者模式实用于数据结构绝对稳固, 算法容易变动的零碎:
- 访问者模式使得算法操作减少变得更加容易
- 若零碎数据结构对象易于变动, 常常有新的对象减少进来, 则不适宜应用访问者模式
-
访问者模式的特点:
-
长处: 减少操作容易
- 减少操作意味着减少新的访问者
- 访问者模式将无关行为集中到一个访问者对象中, 这些行为的扭转不影响零碎数据结构
- 毛病: 减少新的数据结构很艰难
-
- 访问者模式 : 是一种拆散对象数据结构和行为的办法, 通过这种拆散, 能够达到为一个被访问者动静增加新的操作而无需做任何批改的成果
- 一个 Visitor 类, 寄存要拜访的对象
-
Subject类中有 accept 办法, 接管将要拜访的对象 ,getSubject() 获取将要被拜访的属性
- Visitor
public interface Visitor{
public void visit(Subject sub);
} -
MyVisitor
public class MyVisitor implements Visitor{
@Override
public void visit(Subject sub){System.out.println("visit the subject:"+sub.getSubject());
}
} - Subject
public interface Subject{
public void accept(Visitor visitor);
public String getSubject();
} -
MySubject
public class MySubject implements Subject{
@Override
public void accept(Visitor visitor){visitor.visit(this);
}
@Override
public String getSubject(){return "love";
}
} -
Test
public class Test{
public static void main(String[] args){Visitor visitor=new MyVisitor(); Subject sub=new MySubject(); sub.accept(visitor);
}
} -
访客模式实用场景:
-
如果要为一个现有的类减少新性能:
- 新性能是否会与现有性能呈现兼容性问题
- 当前会不会还有新性能须要增加
- 如果类不容许批改代码怎么解决
- 这些问题最好的解决办法就是访客模式
-
访问者模式实用于数据结构绝对稳固的零碎, 将数据结构和算法解耦
中介者模式(Mediator)
-
-
中介者模式是用来升高类与类之间的耦合的:
- 类与类之间有依赖关系的话, 不利于性能的拓展和保护
- 因为只有批改一个对象, 其它关联的对象都要进行批改
- 中介者模式: 只须要关怀 Mediator 类的关系, 具体类与类之间的关系及调度交给 Mediator, 与 Spring 容器的作用相似
- User类对立接口
-
User1和 User2 别离是不同的对象:
- 二者之间有关联
- 如果不采纳中介者模式. 则须要二者互相持有援用, 这样二者的耦合度很高
- 为理解耦, 引入了 Mediator 类, 提供对立接口
-
MyMediator为实现类:
- 持有 User1 和User2的实例, 用来实现对 User1 和User2的管制
- 这样 User1 和User2两个对象就能够互相独立, 只需放弃与 Mediator 之间的关系就能够
-
Mediator类用来保护
-
Mediator
public interface Mediator{
public void createMediator();public void workAll();
} -
MyMediator
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();
}
} -
User
public abstract class User{
private Mediator mediator;public Mediator getMediator(){
return mediator;
}
public User(Mediator mediator){
this.mediator=mediator;
}
public abstract void work();
} -
User1
public class User1 extends User{
public User1(Mediator mediator){super(mediator);
}
@Override
public void work(){System.out.println("user1 exe!");
}
} -
User2
public User2 extends User{
public User2(Mediator mediator){super(mediator);
}
@Override
public void work(){System.out.println("user2 exe!");
}
} -
Test
public class Test{
public static void main(String[] args){Mediator mediator=new MyMediator(); mediator.createMediator(); mediator.workAll();
}
} - 解释器模式个别次要利用在 OOP 开发中的编译器开发中, 实用面比拟窄
- Context类是一个上下文环境类
-
Plus和 Minus 别离是计算的实现
- Expression
public interface Expression{
public int interpret(Context context);
} -
Plus
public class Plus implements Expression{
@Override
public int interpret(Context context){return context.getNum1()+context.getNum2();
}
} -
Minus
public class Minus implements Expression{
@Override
public void interpret(Context context){return context.getNum1()-context.getNum2();
}
} -
Context
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;
}
} -
Test
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);
}
} - 解释器模式是来用作各种各样的解释器