设计模式汇总(23种)
创建型(5种):单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。
结构型(7种):代理模式、适配器模式、装饰者模式、外观模式、桥接模式、组合模式、享元模式。
行为型(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
创建型
单例模式
- 定义:保证一个类仅有一个实例,并提供一个访问该实例的全局访问点。
- 优点:只有一个实例,即共享资源,提供全局使用。以节省创建的时间来提高性能。
饿汉式(线程安全)
/**
* 饿汉式单例模式-线程安全
* @ClassName HungerSingleton
* @Description TODO
* @Author 隔山海
* @date 2020/10/29 19:53
* @Version 1.0
*/
public class HungerSingleton {
private static HungerSingleton safeInstance= new HungerSingleton();
private HungerSingleton(){}
public static HungerSingleton getInstance(){
return safeInstance;
}
}
懒汉式(线程不安全)
public class LazySingleton {
private static LazySingleton unSafeInstance;
private LazySingleton(){}
/**
* 懒汉式-线程不安全
* @return 返回不安全的单例对象
*/
public static LazySingleton getInstanceUnSafe(){
if (unSafeInstance == null){
unSafeInstance = new LazySingleton();
}
return unSafeInstance;
}
}
懒汉式(线程安全)
public class LazySingleton {
private static LazySingleton safeInstance;
private LazySingleton(){}
/**
* 懒汉式-线程安全
* @return 返回安全的单例对象
*/
private static synchronized LazySingleton getInstanceSafe(){
if (safeInstance == null){
safeInstance = new LazySingleton();
}
return safeInstance;
}
}
懒汉式(双重校验锁-线程安全)
public class LazySingleton {
/**
* volatile:对象被修改时第一时间通知其他线程------禁止JVM指令重排
*/
private static volatile LazySingleton doubleSafeInstance;
private LazySingleton(){}
/**
* 懒汉式-双重校验锁-线程安全
* @return 返回安全的单例对象
*/
public static synchronized LazySingleton getUniqueInstanceSafe(){
if(doubleSafeInstance == null){
synchronized (LazySingleton.class){
if (doubleSafeInstance == null){
doubleSafeInstance = new LazySingleton();
}
}
}
return doubleSafeInstance;
}
}
简单工厂模式
- 特点:使用静态方法通过接收参数不同来返回不同的实例
- 扩展方法:在不修改代码的情况下无法扩展
- 优点:工厂类中包含了必要的逻辑,根据用户需求条件动态实例化相关的类,去掉了具体产品的依赖
- 缺点:集中了所有实例的创建逻辑,违反了高内聚,添加新的东西时违反了开放-封闭原则
/**
* @ClassName SimpleFactory
* @Description TODO
* @Author 隔山海
* @date 2020/10/30 16:12
* @Version 1.0
*/
public class SimpleFactory {
public static void main(String[] args) {
// 把产品名称给工厂->工厂生产
SimpleCar car = SimpleFactory.createCar("Bmw");
car.setName("Bmw");
car.drive();
}
public static SimpleCar createCar(String car){
SimpleCar c = null;
if ("Benz".equalsIgnoreCase(car)){
c = new SimpleBenz();
}else if("Bmw".equalsIgnoreCase(car)){
c=new SimpleBmw();
}
return c;
}
}
/**
* 抽象产品
*/
abstract class SimpleCar{
private String name;
public abstract void drive();
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
/**
* 具体产品
*/
class SimpleBenz extends SimpleCar{
@Override
public void drive() {
System.out.println(this.getName()+" "+ "Go");
}
}
/**
* 具体产品
*/
class SimpleBmw extends SimpleCar{
@Override
public void drive() {
System.out.println(this.getName()+ "Go");
}
}
工厂方法模式
- 特点:针对每一种产品提供一个工厂类。
- 扩展方式:在同一等级中可以任意扩展。
- 优点:创建对象的接口,让子类取决定具体实例化的对象,把简单的内部逻辑判断移到了客户端代码,工厂方法客服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。
- 缺点:不易于维护,假如某个具体产品类需要进行一定的修改,很可能需要修改对应得工厂类。当同时需要修改多个产品类得时候,对工厂类得修改会变得相当麻烦。
/**
* @ClassName MethodFactory
* @Description TODO
* @Author 隔山海
* @date 2020/10/30 16:22
* @Version 1.0
*/
public class MethodFactory {
public static void main(String[] args) throws Exception {
// 将图纸给对应的工厂
MethodDrive d = new MethodBmwDrive();
// 工厂造车
MethodCar car = d.createCar();
car.setName("bmw");
car.drive();
}
}
/**
* 抽象产品
*/
abstract class MethodCar{
private String name;
public abstract void drive();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* 具体产品
*/
class MethodBenz extends MethodCar{
@Override
public void drive() {
System.out.println(this.getName()+"Go");
}
}
/**
* 具体产品
*/
class MethodBmw extends MethodCar{
@Override
public void drive() {
System.out.println(this.getName()+"Go");
}
}
/**
* 抽象工厂
*/
abstract class MethodDrive{
public abstract MethodCar createCar();
}
/**
* 具体工厂 -- 生产奔驰
*/
class MethodBenzDrive extends MethodDrive{
@Override
public MethodCar createCar() {
return new MethodBenz();
}
}
/**
* 具体工厂 -- 生产宝马
*/
class MethodBmwDrive extends MethodDrive{
@Override
public MethodCar createCar() {
return new MethodBmw();
}
}
抽象工厂模式
- 特点:针对产品族
- 扩展方式:应对产品族概念,可以增加新的产品线,但无法增加新的产品
- 优点:分离了具体的类,抽象工厂模式帮助你控制一个应用创建的对象的类,客户端通过他们的抽象接口操纵实例,产品的类名也在具体工厂的实现中被分离,他们不出现在客户代码中,使得易于交换产品系列
- 缺点:抽象工厂模式在于难于应付“新对象”的需求变动。难以支持新种类的产品。难于扩展抽象工厂以生产新中类的产品。
/**
* @ClassName AbstractFactory
* @Description TODO
* @Author 隔山海
* @date 2020/10/30 17:39
* @Version 1.0
*/
public class AbstractFactory {
public static void main(String[] args) {
// 构建商务款的工厂
Factory businessFactory = new BusinessFactory();
// 构建商务奥迪生产线
AudiCar businessAudi = businessFactory.createAudiCar("奥迪-商务");
// 构建商务奔驰生产线
BenzCar businessBenz = businessFactory.createBenzCar("奔驰-商务");
// 构建商务宝马生产线
BmwCar businessBmw = businessFactory.createBmwCar("宝马-商务");
businessAudi.drive();
businessBenz.drive();
businessBmw.drive();
// 构建运动款的工厂
Factory sportFactory = new SportFactory();
AudiCar sportAudi = sportFactory.createAudiCar("奥迪-运动");
BenzCar sportBenz = sportFactory.createBenzCar("奔驰-运动");
BmwCar sportBmw = sportFactory.createBmwCar("宝马-运动");
sportAudi.drive();
sportBenz.drive();
sportBmw.drive();
}
}
/******************************************************抽象产品
* 抽象产品 - 奔驰车
*/
abstract class BenzCar{
private String name;
public abstract void drive();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
BenzCar(String name){
this.name = name;
}
}
/**
* 抽象产品 - 宝马车
*/
abstract class BmwCar{
private String name;
public abstract void drive();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
BmwCar(String name){
this.name = name;
}
}
/**
* 抽象产品 - 奥迪车
*/
abstract class AudiCar{
private String name;
public abstract void drive();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
AudiCar(String name){
this.name = name;
}
}
/**********************************************具体产品
* 具体产品 - 奔驰运动款
*/
class BenzSportCar extends BenzCar{
BenzSportCar(String name) {
super(name);
}
@Override
public void drive() {
System.out.println(this.getName()+"----BenzSportCar-----------------------");
}
}
/**
* 具体产品 - 奔驰商务款
*/
class BenzBusinessCar extends BenzCar{
BenzBusinessCar(String name) {
super(name);
}
@Override
public void drive() {
System.out.println(this.getName()+"----BenzBusinessCar-------------");
}
}
/**
* 具体产品 - 宝马运动款
*/
class BmwSportCar extends BmwCar{
BmwSportCar(String name) {
super(name);
}
@Override
public void drive(){
System.out.println(this.getName()+"----BmwSportCar-----------------");
}
}
/**
* 具体产品 - 宝马商务款
*/
class BmwBusinessCar extends BmwCar{
BmwBusinessCar(String name) {
super(name);
}
@Override
public void drive(){
System.out.println(this.getName()+"----BmwBusinessCar---------------");
}
}
/**
* 具体产品 - 奥迪运动款
*/
class AudiSportCar extends AudiCar{
AudiSportCar(String name) {
super(name);
}
@Override
public void drive(){
System.out.println(this.getName()+"----AudiSportCar---------------------");
}
}
/**
* 具体产品 - 奥迪商务款
*/
class AudiBusinessCar extends AudiCar{
AudiBusinessCar(String name) {
super(name);
}
@Override
public void drive(){
System.out.println(this.getName()+"----AudiBusinessCar-----------------");
}
}
/*****************************************************抽象工厂
* 抽象工厂
*/
abstract class Factory{
public abstract BenzCar createBenzCar(String car);
public abstract BmwCar createBmwCar(String car);
public abstract AudiCar createAudiCar(String car);
}
/**************************************************具体工厂
* 具体工产 - 运动款工厂
*/
class SportFactory extends Factory{
@Override
public BenzCar createBenzCar(String car) {
return new BenzSportCar(car);
}
@Override
public BmwCar createBmwCar(String car) {
return new BmwSportCar(car);
}
@Override
public AudiCar createAudiCar(String car) {
return new AudiSportCar(car);
}
}
/**
* 具体工厂 - 商务款工厂
*/
class BusinessFactory extends Factory{
@Override
public BenzCar createBenzCar(String car) {
return new BenzBusinessCar(car);
}
@Override
public BmwCar createBmwCar(String car) {
return new BmwBusinessCar(car);
}
@Override
public AudiCar createAudiCar(String car) {
return new AudiBusinessCar(car);
}
}
结构型
代理模式
- 定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介 。
静态代理模式
/**
* 代理类--代理类和委托类实现统一个接口:通过代理类调用委托类的方法
* @ClassName StaticProxy
* @Description TODO
* @Author 隔山海
* @date 2020/10/29 19:59
* @Version 1.0
*/
public class StaticProxy implements IStaticService{
private IStaticService proxyService = new StaticProxyServiceImpl();
@Override
public String proxyMethod(String methodName) {
return proxyService.proxyMethod(methodName);
}
/**
* 测试静态代理
* @param args
*/
public static void main(String[] args) {
StaticProxy staticProxy = new StaticProxy();
System.out.println(staticProxy.proxyService.proxyMethod("嗯哼?"));
}
}
/**
* 委托接口
*/
interface IStaticService{
/**
* 代理方法
* @param methodName methodName
* @return 返回methodName
*/
String proxyMethod(String methodName);
}
/**
* 委托类实现
*/
class StaticProxyServiceImpl implements IStaticService {
@Override
public String proxyMethod(String methodName) {
return "methodName:"+methodName;
}
}
JDK动态代理
**
* @ClassName JdkProxy
* @Description TODO
* @Author 隔山海
* @date 2020/10/29 20:18
* @Version 1.0
*/
public class JdkProxy {
/**
* 测试动态代理类
* @param args args
*/
public static void main(String[] args) {
JdkProxyInvocationHandler handler = new JdkProxyInvocationHandler(new JdkServiceImpl());
IJdkService service = (IJdkService) handler.getInstance();
System.out.println(service.proxyMethod("哟吼吼?"));
}
}
/**
* 中间类
*/
class JdkProxyInvocationHandler implements InvocationHandler{
/**
* 中间类吃哦有委托类的引用,这里会构成一种静态代理关系
*/
private Object obj;
/**
* 有参构造器,传入委托对象
* @param obj 委托类的对象
*/
public JdkProxyInvocationHandler(Object obj){
this.obj = obj;
}
/**
* 动态生成代理类对象,Proxy.newProxyInstance
* @return 返回代理类的实例
*/
public Object getInstance(){
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
}
/**
* @param proxy 代理对象
* @param method 代理方法
* @param args 方法的参数
* @return return
* @throws Throwable Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke before");
Object invoke = method.invoke(obj, args);
System.out.println("invoke after");
return invoke;
}
}
/**
* 委托类接口
*/
interface IJdkService{
/**
* 委托方法
* @param methodName methodName
* @return 返回methodName
*/
String proxyMethod(String methodName);
}
/**
* 委托类
*/
class JdkServiceImpl implements IJdkService{
@Override
public String proxyMethod(String methodName) {
System.out.println("在调用proxyMethod中...");
return methodName;
}
}
CGLIB动态代理
/**
* cglib代理
* @ClassName Cglib
* @Description TODO
* @Author 隔山海
* @date 2020/10/29 20:50
* @Version 1.0
*/
public class Cglib {
public static void main(String[] args) {
CglibInterceptor cglibInterceptor = new CglibInterceptor();
ServiceImpl service = (ServiceImpl) cglibInterceptor.newInstance(ServiceImpl.class);
System.out.println(service.sayHello("陈少磊"));
}
}
/**
* 委托类-一个简单的类
*/
class ServiceImpl{
public String sayHello(String userName){
System.out.println("目标对象的方法执行了");
return userName;
}
}
class CglibInterceptor implements MethodInterceptor {
/**
* CGLIB 增强对象,代理类对象是由Enhancer类创建的
* Enhancer时CGLIB的字节码增强器,可以方便的对类进行拓展
*/
private Enhancer enhancer = new Enhancer();
/**
* 使用动态代理创建一个对象
* @param clazz clazz
* @return 返回代理对象
*/
public Object newInstance(Class<?> clazz){
/**
* 设置产生的代理对象的父类,增强类型
*/
enhancer.setSuperclass(clazz);
/**
* 定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor接口
*/
enhancer.setCallback(this);
/**
* 使用默认无参构造创建目标对象,被代理对象的类要提供无参构造器
*/
return enhancer.create();
}
/**
*
* @param obj obj
* @param method method
* @param args args
* @param proxy proxy
* @return return
* @throws Throwable Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before");
Object o = proxy.invokeSuper(obj, args);
System.out.println("after");
return o;
}
}
行为型
策略模式
- 策略模式就是能够把一系列算法封装起来,并根据用户需求来选择其中一种。我们可以通过这种模式将一个父类中会变化的部分提取并封装起来,以便此后可以轻易地改变或者扩展这部分,而不影响其他部分。
/**
* @ClassName Strategy
* @Description TODO
* @Author 隔山海
* @date 2020/10/29 21:25
* @Version 1.0
*/
public class Strategy {
public static void main(String[] args) {
Context context = new Context(new AddStrategy());
System.out.println("10+5="+context.executeStrategy(10,5));
context = new Context(new SubStrategy());
System.out.println("10-5="+context.executeStrategy(10,5));
context = new Context(new MulStrategy());
System.out.println("10*5="+context.executeStrategy(10,5));
context = new Context(new DivStrategy());
System.out.println("10/5="+context.executeStrategy(10,5));
}
}
/**
* 使用Context改变策略
*/
class Context{
private IStrategy strategy;
public Context(IStrategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1,int num2){
return strategy.doOperation(num1,num2);
}
}
interface IStrategy{
/**
* 策略接口方法
* @param num1 num1
* @param num2 num2
* @return 返回计算值
*/
public int doOperation(int num1,int num2);
}
/**
* 相加策略
*/
class AddStrategy implements IStrategy{
@Override
public int doOperation(int num1, int num2) {
return num1+num2;
}
}
/**
* 相减策略
*/
class SubStrategy implements IStrategy{
@Override
public int doOperation(int num1, int num2) {
return num1-num2;
}
}
/**
* 相乘策略
*/
class MulStrategy implements IStrategy{
@Override
public int doOperation(int num1, int num2) {
return num1*num2;
}
}
/**
* 相除策略
*/
class DivStrategy implements IStrategy{
@Override
public int doOperation(int num1, int num2) {
return num1/num2;
}
}