设计模式
为什么要用设计模式?
设计模式是编程随时间发展下来总结的经验和套路,它可以让写出来的代码复用性更好、拓展性更强、易于维护等等优点
设计模式的类型
创建型模式
提供一种在创建对象的同时隐藏创建逻辑的方式,让程序在不同情境下可以灵活的选择创建对象的类型
工厂模式、抽象工厂模式、单例模式、建造者模式等
结构型模式
常见的设计模式
工厂模式
意图:定义一个工厂接口,实现不同的创建对象方式,使用者直接使用实现类创建对象。
优点:
- 可以屏蔽复杂的创建过程,调用者只关心通过哪个工厂创建。
- 扩展性强,如果需要添加一种创建方式,只需要实现一个新的工厂类
缺点:
- 每次定义一种类的时候就需要一个配套的对象工厂,一定程度上增加了复杂度,所以如果简单的类型直接new就好了。
使用场景:
- Spring的BeanFactory接口就是工厂模式,它的实现类可以通过配置文件的信息生产Bean,也可以通过getBean获取实例时就是向工厂获取指定的Bean
抽象工厂模式
与简单工厂模式的区别
简单工厂模式只针对单个”产品的生产“,而抽象工厂模式中有多个产品需要生产,并且各个产品之间又有依赖关系。
例子:
我们需要生产矿泉水,如果用简单工厂模式就是需要三个工厂,一个产水一个产瓶子,然后还要有一个工厂把水填进瓶子里。显然水和瓶子是有逻辑上的关系的,使用抽象工厂模式后,在抽象工厂中定义生产水、生产瓶子和灌装水的方法,具体的实现类都实现后就可以在一个工厂中生产出矿泉水了。
单例模式
意图: 保证一个类只有一个实例,全局只访问这一个,避免一个相同的类被频繁的创建和销毁
例子:
- Spring当中的Bean默认都是单例模式
- 计数器使用的也是单例,然后保证同步访问。
- 数据库的连接池也算吧,固定几个连接,它们都是不同的对象,可以理解成单个?然后实现复用
懒汉式实现
//懒汉式实现是在实际使用时才创建 public class Singleton { private static Singleton singleton = null; // 构造得声明成私有的,不会被外部随意实例化 private SingleTon(){} // 方法体加锁 public static synchronized SingleTon() { if (singleton == null) { singleton = new Singleton(); } return singleton; } // 双重锁定 public static SingleTon() { // 两次判空是因为,等待锁时可能已经被人初始化过了,如果不再判断可能会重复初始化。 if (singleton == null) { synchronized(this) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
饿汉式实现
// 饿汉式在类初始化时就已经初始化了静态实例 public class Singleton { private static Singleton singleton = new Singleton(); private SingleTon(){} public static SingleTon() { return singleton; } }
建造者模式
意图: 将一个复杂对象的创建分离成各个步骤,使得一个复杂对象可以在多次组合当中创建出来。
实例:
- StringBuilder就是其中一种,例如输出一段日志的前缀都是相同的,但是程序执行中可能成功或者失败,那么可以根据不同的结果append拼接,最后组合出整个字符串对象。
适配器模式
意图: 适配器模式使得原本不相兼容的接口可以一起工作,日常生活中常见的图片查看器就是一种“适配器”,可以查看不同格式的图片。
实例:
- SpringMVC中就有HandleAdepter,用于适配Controller的不同实现方式(注解、配置、实现Controller接口、实现HTTPRequestHandle接口)的调用。
实现
public interface JPG extend PictureFormat{ void display(); } public class JPGPlayer{ void display(){ .... } } public interface PicturePlayer { void displayPicture(); } public class PlayerAdepter implement PicturePlayer{ PictureFormat format = null; public PlayerAdepter(PictureFormat format){ this.format = format; } void displayPicture() { // 额外处理 format.display(); // 额外处理 } }
装饰器模式
意图: 动态地给一个对象添加一些额外的功能,同时不改变其原有的结构。相比起继承装饰者模式更加灵活。
实例:
- JDK 中Collections.SynchronizedMap,生成线程安全的集合类,将其所有修改方法都加上了同步锁
实现:
public interface Human { void talk(); } public class Man implement Human{ void talk(){ //打印hello } } public abstract class HumanDecorator implement Human { private Human human = null; public HumanDecorator(Human human) { this.human = human; } void talk() { human.talk(); } } public class StudentDecorator extends HumanDecorator { public StudentDecorator(Human human) { super(human); } @Override void talk() { human.talk(); readBook(); } private void readBook(){ //读书 } }
代理模式
意图: 为其他对象提供一种代理的方式控制这个对象的访问。
实例:
- JDK中的动态代理
- Spring AOP
与适配器模式的区别
适配器模式需要考虑其中对不同对象的适配,代理模式代理的对象一旦确定是不能改变的
与装饰者模式的区别
其实差别不大,只是使用的本意不同,装饰器模式是为了增加额外的功能,代理模式是为了加以控制
实现:
静态代理、动态代理、
观察者模式
意图: 定义对象之间一种一对多的依赖关系,当一个对象的状态发生改变时,通知依赖于它的观察者对象执行对应的处理方法。它类似于广播通讯。用途可以用于广播通知更改、也可以做一个回调机制
实例:
- Spring的事件驱动模型就是观察者模式的应用,它有各种Listener对应到各个事件中,例如ApplicationContext初始化完成后打印日志、Environment环境对象初始化完成后读取用户的Application.properties等等
实现:
- 首先得定义事件类型Event,和一个或者多个Listener,Listener统一实现一个接口的事件触发执行方法。
- 事件中心类EventObject中维护Event和Listener的一对多关系。
- 从事件中心类中发布事件后,调用对应事件中的所有观察者。
策略模式
意图: 定义一系列函数,把他们封装起来,并且使他们之间能互相替换,它可以解决在有多种解决方式的情况下使用if..else所带来的复杂度。
实现:
public interface Strategy{ void algorithmInterface(); } public class ConcreteStrategyA extends Strategy { @Override public void algorithmInterface() { System.out.println("算法A实现"); } } public class ConcreteStrategyB extends Strategy { @Override public void algorithmInterface() { System.out.println("算法B实现"); } } public class Client { public static void main(String[] args) { Context context; context = new Context(new ConcreteStrategyA()); context.contextInterface(); context = new Context(new ConcreteStrategyB()); context.contextInterface(); context = new Context(new ConcreteStrategyC()); context.contextInterface(); } }
模板模式
意图:定义一个程序执行流程的骨架,封装好公共的步骤,将一些步骤延迟到子类当中实现。
实例:
Spring中的各种Template类,RedisTemplate、JDBCTemplate等
实现:
public abstract class Template { abstract void run(); abstract void destroy(); void init() { System.out.println("初始化"); } public final void play(){ init(); run(); destroy(); } } class GameTemplate extends Template { @Override void run() { System.out.println("执行"); } @Override void destroy() { System.out.println("销毁"); } }