java设计模式入门
java设计模式是为了增加代码的可复用性,可维护性,可扩展性,灵活性。
可复用性:可以重复使用
可维护性:要改动时只需要改需要改的地方
可扩展性:需要什么功能另外加上去就行了
灵活性:可以根据不同需求而使用
设计模式分为三种和六大原则
(1)创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
(2)结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
(3)行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
1、开闭原则:只能扩展新的,不能修改原有代码
2、里氏替换原则:子类的能力必须大于等于父类,即父类可以使用的方法,子类都可以使用 。
3、依赖倒转原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象
4、接口隔离原则:使用多个隔离的接口,而不使用单一的总接口,降低耦合
5、迪米特法则:个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则:原则是尽量使用合成/聚合的方式,而不是使用继承
单例模式
单例模式是比较常见的一种设计模式,目的是保证一个类只能有一个实例,而且自行实例化并向整个系统提供这个实例,避免频繁创建对象,节约内存。
懒汉式
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉式
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton(){} public static Singleton getInstance(){
return INSTANCE;
}}
双重校验锁
public class SingleTon3 {
private SingleTon3(){}; //私有化构造方法
private static volatile SingleTon3 singleTon=null;
public static SingleTon3 getInstance(){
//第一次校验
if(singleTon==null){
synchronized(SingleTon3.class){
//第二次校验
if(singleTon==null){
singleTon=new SingleTon3();
}
}
}
return singleTon;
}
为什么需要两次判断if(singleTon==null)?
分析:第一次校验:由于单例模式只需要创建一次实例,如果后面再次调用getInstance方法时,则直接返回之前创建的实例,因此大部分时间不需要执行同步方法里面的代码,大大提高了性能。如果不加第一次校验的话,那跟上面的懒汉模式没什么区别,每次都要去竞争锁。
第二次校验:如果没有第二次校验,假设线程t1执行了第一次校验后,判断为null,这时t2也获取了CPU执行权,也执行了第一次校验,判断也为null。接下来t2获得锁,创建实例。这时t1又获得CPU执行权,由于之前已经进行了第一次校验,结果为null(不会再次判断),获得锁后,直接创建实例。结果就会导致创建多个实例。所以需要在同步代码里面进行第二次校验,如果实例为空,则进行创建。
需要注意的是,private static volatile SingleTon3 singleTon=null;需要加volatile关键字,否则会出现错误。问题的原因在于JVM指令重排优化的存在。在某个线程创建单例对象时,在构造方法被调用之前,就为该对象分配了内存空间并将对象的字段设置为默认值。此时就可以将分配的内存地址赋值给instance字段了,然而该对象可能还没有初始化。若紧接着另外一个线程来调用getInstance,取到的就是状态不正确的对象,程序就会出错。
模板方法模式
抽象父类定义需要实现单个方法和顶层逻辑(模板方法),子类实现父类的单个方法,创建父类的字类实例调用顶层逻辑实现模板方法。
例子:
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//模板
public final void play(){
//初始化游戏
initialize();
//开始游戏
startPlay();
//结束游戏
endPlay();
}
}
public class Football extends Game {
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}
public class TemplatePatternDemo {
public static void main(String[] args) {
Game game = new Football();
game.play();
}
}
原型模式
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
当创建相同对象的时候,使用拷贝减少资源消耗达到高性能创建新的相同对象
其中要重新clone实现深拷贝(直接拷贝,序列化)
观察者模式
存在一对多的依赖关系时,使用观察者模式实现当Subject发生修改,Observer 通知到其他client。
即使用Observer观察者使Subject的消息可以通知到各个client,client到Obsever上注册/移除,当subject发生改变时,通知到observer,observer通知当前注册的所有client即为观察者模式