设计模式总结(Java)

Posted 覃会程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式总结(Java)相关的知识,希望对你有一定的参考价值。

文章目录

面向对象设计的基本原则:

  • OCP (开闭原则, Open-Closed Principle) : 一个软件的实体应当对扩展开放,对修改关闭。即当要添加一个新功能时,不要修改已有的类,而是重新写一个类实现这个功能。
  • DIP (依赖倒转原则, Dependence Inversion Principle ) : 要针对接口编程,不要针对实现编程。
  • LoD (迪米特法则, Law of Demeter) : 只与你直接的朋友通信,而避免和陌生人通信。

创建型模式




单例模式 (常用)

作用:
  保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。


常见应用场景:

  • Windows的Task Manager (任务管理器)就是很典型的单例模式
  • windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程中,回收站-直维护着仅有的一个实例。
  • 项目中,读取配置文件的类, 一般也只有一个对象。 没有必要每次使用配置文件数据,每次new-个对象去读取。
  • 网站的计数器, 一般也是采用单例模式实现,否则难以同步。
  • 应用程序的日志应用, 一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态 ,因为只能有一个实例去操作,否则内容不好追加。
  • 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。
  • 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
  • Application也是单例的典型应用( Servlet编程中会涉及到)
  • 在Spring中,每个Bean默认就是单例的,这样做的优点是Spring容器可以管理
    在servlet编程中,每个Servlet也是单例
  • 在spring MVC框架/struts1框架中,控制器对象也是单例

单例模式的优点:

  • 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
  • 单例模式可以在系统设置全局的访问点 ,优化环共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理

常见的五种单例模式实现方式:

  • 主要:
    • 饿汉式(线程安全,调用效率高。但是,不能延时加载。)
    • 懒汉式(线程安全,调用效率不高。 但是,可以延时加载。);在用的使用才加载。并发效率资源第。
  • 其他:
    • 双重检测锁式(由于JVM底层内部模型原因,偶尔会出问题。不建议使用);这个模式将同步内容下方到if内部,提高了执行的效率不必每次获取对象时都进行同步,只有第一次才同步创建了以后就没必要了。
    • 静态内部类式(线程安全,调用效率高。但是,可以延时加载);也是一种懒加载的方式。兼备了并发高效调用和延迟加载的优势!
    • 枚举单例(线程安全,调用效率高,不能延时加载);实现简单,枚举本身就是单例模式。由JVM从根本上提供保障!避免通过反射和反序列化的漏洞!

如何选用
单例对象占用资源少,不需要延时加载:

  • 枚举式好于饿汉式

单例对象占用资源大,需要延时加载:

  • 静态内部类式好于懒汉式

五种单例模式的代码实现:

饿汉模式:

/*
 * 饿汉式单例模式
 */
public class SingletonDemo1 
	
	//初始化类时,立即加载这个对象(没有延时加载的优势,因为不一定要使用,立即加载可能会浪费资源)
	//加载类时,因为创建对象是线程安全的,不需要添加关键字synchronized(加锁),所以饿汉式是天然线程安全的
	private static SingletonDemo1 instance = new SingletonDemo1();
	
	//将构造方法私有化
	private SingletonDemo1()
	
	
	//提供一个获得对象的方法,方法没有同步,调用效率高
	public static SingletonDemo1 getInstance()
		return instance;
	


懒汉式:

/* 
 * 懒汉式单例模式
 */
public class SingletonDemo2 
	
	//类初始化时,不立即初始化对象(延时加载,在要使用的时候才进行加载)
	private static SingletonDemo2 instance;
	
	//将构造方法私有化
	private SingletonDemo2()
	
	
	//方法同步,调用效率高
	public static synchronized SingletonDemo2 getInstance()
		if(instance==null)
			instance = new SingletonDemo2();
		
		return instance;
	



双重检测锁式:

/* 
 * 双重检测锁式单例模式
 */
public class SingletonDemo3 
	
	private static SingletonDemo3 instance = null;
	
	//将构造方法私有化
	private SingletonDemo3()
	
	
	//这个模式将同步内容下方到if内部,提高了执行的效率不必每次获取对象时都进行同步,只有第一次才同步创建了以后就没必要了。
	public static  SingletonDemo3 getInstance()
		if(instance==null)
			SingletonDemo3 sc;
			synchronized(SingletonDemo3.class)
				sc = instance;
				if(sc==null)
					synchronized(SingletonDemo3.class)
						if(sc==null)
							sc = new SingletonDemo3();
						
					
					instance = sc;
				
			
		
		return instance;
	



静态内部类式:

/* 
 * 静态内部类式单例模式
 */
public class SingletonDemo4 
	/*
	 * 要点:
		-外部类没有static属性,则不会像饿汉式那样立即加载对象。
		-只有真正调用getInstance0,才会加载静态内部类。加载类时是线程安全的。 instance是static final
		类型,保证了内存中只有这样一个实例存在 ,而且只能被赋值一次,从而保证了线程安全性.
		-兼备了并发高效调用和延迟加载的优势!
	 */ 
	private static class SingletonClassInstance
		private static final SingletonDemo4 instance = new SingletonDemo4();
	
	
	public static SingletonDemo4 getinstance()
		return SingletonClassInstance.instance;
	
	
	//将构造方法私有化
	private SingletonDemo4()
	
	



枚举式:

/*
 * 枚举式单例模式
 */
public enum SingletonDemo5 
	
	//这个枚举元素,本事就是单例; 缺点是不能延时加载
	INSTANCE;
	
	//添加自己需要的操作
	public void singletonOperarion()
		
	


  以上五种单例模式除了枚举式,其他的都有可能会被反射和反序列化破解;下面方式可以防止这种情况的发生。

import java.io.ObjectStreamException;

/* 
 * 懒汉式单例模式(防止通过反射和反序列化进行破解)
 */
public class SingletonDemo6 
	
	//类初始化时,不立即初始化对象(延时加载,在要使用的时候才进行加载)
	private static SingletonDemo6 instance;
	
	//将构造方法私有化
	private SingletonDemo6()
		//防止通过反射使用私有的构造器
		if(instance!=null)
			throw new RuntimeException();
		
	
	
	//方法同步,调用效率高
	public static synchronized SingletonDemo6 getInstance()
		if(instance==null)
			instance = new SingletonDemo6();
		
		return instance;
	
	
	//防止通过反序列化破坏单例模式,如果定义了readResolve()则直接返回此方法指定的对象。不需要单独再创建新对象
	private Object readResolve() throws ObjectStreamException
		return instance;
	


五种单例模式在多线程下的效率情况:


注:数据在不同的环境下可能会有点偏差。




工厂模式 (常用)

作用:
  实现了创建者和调用者的分离。

  1. 解耦
    通过工厂模式可以把对象的创建和使用过程分割开来。比如说 Class A 想调用 Class B的方法,那么我们无需关心B是如何创建的,直接去工厂获取就行。

  2. 减少代码量,易于维护
    如果我们直接new一个对象时,如果需要的对象构造方法比较复杂,那么可能需要一连串的代码去创建对象,如果在别的类中又需要创建该对象,那么代码的重复度肯定不小。通过工厂模式的话,我们把对象创建的具体逻辑给隐藏起来了,交给工厂统一管理,这样不仅减少了代码量,以后如果想改代码的话,只需要改一处即可,也方便我们日常的维护。

核心本质:

  • 实例化对象,用工厂方法代替new操作。
  • 将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。

工厂模式的分类:

  • 简单工厂模式:
    • 用来生产同一等级结构中的任意产品。 (对于增加新的产品,需要修改已有代码)
    • 虽然某种程度不符合设计原则,但实际使用最多
  • 方法模式:
    • 用来生产同一等级结构中的固定产品。( 支持增加任意产品);缺点:需要的类可能太多了。
    • 不修改已有类的前提下,通过增加新的工厂类实现扩展。
  • 抽象工厂模式:
    • 用来生产不同产品族的全部产品。( 对于增加新的产品,无能为力;支持增加产品族)
    • 不可以增加产品,可以增加产品族

应用场景

  • JDK中Calendar的getInstance方法
  • JDBC中Connection对象的获取
  • Hibernate中SessionFactory创建Session
  • spring中IOC容器创建管理bean对象
  • XML解析时的DocumentBuilderFactory创建解析器对象
  • 反射中Class对象的newInstance()
  • 对象实例创建的过程比较复杂,并且需要准备很多参数等等,比如说 spring的beanFactory

三种模式下的代码实现和UML图:

用于测试的类:

public interface Car 
	void run();

public class Audi implements Car
	@Override
	public void run() 
		System.out.println("奥迪在跑");
	

public class Byd implements Car
	@Override
	public void run() 
		System.out.println("比亚迪在跑");
	


简单工厂实现:

/*
 * 简单工厂类
 */
public class CarFactory1 
	
	public static Car createAudi()
		return new Audi();
	
	
	public static Car createByd()
		return new Byd();
	

测试类:

/*
 * 简单工厂情况下
 */
public class Client02 
	public static void main(String[] args) 
		Car c1 = CarFactory1.createAudi();
		Car c2 = CarFactory1.createByd();
		 
		c1.run();
		c2.run();
	


简单工厂下的UML图:


方法模式工厂:

工厂方法模式要点:

  • 为了避免简单工厂模式的缺点,不完全满足OCP。
  • 工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目或者一个独立模块而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类。
  • 每一种产品都有一个工厂类对应,当需要添加产品时,只需要添加新的类即可,不需要修改原来的代码。

代码实现:

接口:

public interface CarFactory 
	Car createCar();

奥迪工厂:

public class AudiFactory implements CarFactory

	@Override
	public Car createCar() 
		return new Audi();
	

比亚迪工厂:

public class BydFactory implements CarFactory

	@Override
	public Car createCar() 
		return new Byd();
	

测试类:

/*
 * 使用方法工厂模式
 */
public class Client03 
	public static void main(String[] args) 
		Car c1 = new AudiFactory().createCar();
		Car c2 = new BydFactory().createCar();
		
		c1.run();
		c2.run();
	


方法工厂的UML图:


抽象工厂模式:

作用:

  • 用来生产不同产品族的全部产品。( 对于增加新的产品,无能为力;支持增加产品族)
  • 抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。

代码实现:

引擎产品:

package abstractFactory;
/*
 *引擎接口 
 */
public interface Engine 
	void run();
	void start();


//高端引擎
class LuxuryEngine implements Engine

	@Override
	public void run() 
		System.out.println("转的快!");
	

	@Override
	public void start() 
		System.out.println("启动快!可以自动暂停");
	


//低端引擎
class LowEngine implements Engine

	@Override
	public void run() 
		System.out.println("转的慢!");
	

	@Override
	public void start() 
		System.out.println("启动慢!");
	

座椅产品:

package abstractFactory;
/*
 * 座椅
 */
public interface Seat 
	void massage();


//高端座椅
class LuxurySeat implements Seat

	@Override
	public void massage() 
		System.out.println("可以自动按摩");
	


//低端座椅
class LowSeat implements Seat

	@Override
	public void massage() 
		System.out.println("不能自动按摩");
	

轮胎产品:

package abstractFactory;

//轮胎接口
public interface Tyre 
	void revolve();


//高端轮胎
class LuxuryTyre implements Tyre

	@Override
	public void revolve() 
		System.out.println("旋转不磨损");
	


//低端轮胎
class LowTyre implements Tyre

	@Override
	public void revolve() 
		System.out.println("旋转磨损");
	

工厂接口:

package abstractFactory;

public interface CarFactory 
	Engine CreateEngine();
	Seat CreateSeat();
	Tyre CreateTre();


高端产品族工厂:

package abstractFactory;
/*
 * 高端产品族工厂
 */
public class LuxuryCarFactory implements CarFactory

	@Override
	public Engine CreateEngine() 
		return new LuxuryEngine();
	

	@Override
	public Seat CreateSeat() 
		return new  LuxurySeat();
	

	@Override
	public Tyre CreateTre() 
		return new LuxuryTyre();
	
	


低端产品族工厂:

package abstractFactory;
/*
 * 低端产品族工厂
 */
public class LowCarFactory implements CarFactory

	@Override
	public Engine CreateEngine() 
		return new LowEngine();
	

	@Override
	public Seat CreateSeat() 
		return new  LowSeat();
	

	@Override
	public Tyre CreateTre() 
		return new LowTyre();
	
	

测试类:

package abstractFactory;

public class Client 
	public static void main(String[] args) 
		CarFactory factory = new LuxuryCarFactory();
		Engine e = factory.CreateEngine();
		e.run();
		e.start();
	




建造者模式 (常用)

应用场景:

  • 我们要建造一个复杂的产品。比如:神州飞船,Iphone。这个复杂的产品的创建。有这样个问题需要处理:装配这些子组件是不是有个步骤问题?
  • 实际开发中,我们所需要的对象构建时,也非常复杂,有很多步骤需要处理时。

建造模式的本质:

  • 分离了对象子组件的单独构造(由Builder来负责)和装配(由Director负责)。从而可以构造出复杂的对象。这个模式适用于:某个对象的构建过程复杂的情况下使用。
  • 由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象;相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算法的解耦,实现了更好的复用。

开发中应用场景:

  • StringBuilder类的append方法
  • SQL中的PreparedStatement
  • JDOM中, DomBuilder、SAXBuilder

代码实现和UML图

飞船和零件类:

package 建造者模式;
/*
 * 宇宙飞船
 */
public class AirShip 
	private OrbitalModule orbitalModule;   //轨道舱
	private Engine engine; 		//发动机
	private EscapeTower escapeTower;  //逃逸塔
	
	public void launch()
		System.out.println("发射!");
	
	
	public OrbitalModule getOrbitalModule() 
		return orbitalModule;
	
	public void setOrbitalModule(OrbitalModule orbitalModule) 
		this.orbitalModule = orbitalModule;
	
	public Engine getEngine() 
		return engine;
	
	public void setEngine(Engine engine) 
		this.engine = engine;
	
	public EscapeTower getEscapeTower() 
		return escapeTower;
	
	public void setEscapeTower(EscapeTower escapeTower) 
		this.escapeTower = escapeTower;
	
	
	


class OrbitalModule 
	private String name;

	public OrbitalModule(String name) 
		super();
		this.name = name;
	


class Engine 
	private String name;

	public Engine(String naem) 
		super();
		this.name= naem;
	

	public String getName() 
		return name;
	


class EscapeTower 
	private String name;

	public EscapeTower(String name) 
		super();
		this.name = name;
	

建造者接口:

/*
 * 建造者接口
 */
public interface AirShipBuilder 
	Engine builderEngine();
	O

以上是关于设计模式总结(Java)的主要内容,如果未能解决你的问题,请参考以下文章

JAVA设计模式——抽象工厂模式案例实现

JAVA设计模式--抽象工厂模式

2.java设计模式-抽象工厂模式

Java设计模式:Abstract Factory(抽象工厂)模式

设计模式抽象工厂模式 ( 简介 | 适用场景 | 优缺点 | 产品等级结构和产品族 | 代码示例 )

#yyds干货盘点#-设计模式分享-抽象工厂模式