java中设计模式的运用_java 设计模式的运用-程序员宅基地

技术标签: java  设计模式  开发语言  



前言

java的版本不断的迭代更新,各种框架和组件也层出不穷,但是设计的思想永远不会变,也许平时只是一个curl工程师,还在代码中看不到任何设计模式的影子,那可太糟心了。设计模式的应用往往也能反应一个程序员的水平,设计模式说到底就是可扩展 可解耦 多封装一些共用行为,就是为了提升代码的可读可用性,设计模式就像写文章一样,没有对错之分,一条语句可以有多种表达方式 修辞手法。


一、单例模式

保证类只产生有且只有一个实例。由私有构造函数,共用访问点,一个静态初始变量组成。单例模式分饿汉和懒汉。

1.饿汉

饿汉不管需不需要直接实例化,不用考虑多线程冲突问题,可用于配置文件初始化。

package com.orange.demo.design;

public class Single {
    

    private static Single instance = new Single();

    // 禁止外部实例化
    private Single(){
    }

    public static Single getInstance(){
    
        return instance;
    }

    public void execute(){
    
        System.out.println("饿汉");
    }

    public static void main(String[] args){
    
        Single single = Single.getInstance();
        single.execute();
    }
}

2.懒汉

懒汉是调用时才实例化,线程不安全,可通过双锁机制保证线程安全,多用于对外部客户端的初始化

package com.orange.demo.design;

public class Single {
    

    private static volatile Single instance;//禁止指令重排

    // 禁止外部实例化
    private Single(){
    }

    public static Single getInstance(){
    
        if (instance==null) {
    
            synchronized (Single.class){
    
                if (instance==null) {
    //防止拿到锁后对象已经实例化
                    instance = new Single();
                }
            }
        }
        return instance;
    }

    public void execute(){
    
        System.out.println("懒汉");
    }

    public static void main(String[] args){
    
        Single single = Single.getInstance();
        single.execute();
    }
}

二、装饰器模式

故名思意,作为一个装饰品添加到原有功能上,不对原有代码做变更,spring中的过滤器和AOP拦截器都是装饰器模式。
装饰器模式由装饰类和被装饰类组成,装饰类继承被装饰类,将被装饰类实例传入装饰类,类似生成一个代理类。

package com.orange.demo.design;

public class House {
    

    public House() {
    
    }

    void door(){
    
        System.out.println("我是一扇门");
    }
}
package com.orange.demo.design;

public class Decorator extends House {
    

    private House house;

    public Decorator(House house) {
    
        this.house = house;
    }

    @Override
    void door() {
    
        super.door();
        System.out.println("添加一些装饰");
    }

    public static void main(String[] args){
    
        Decorator decorator = new Decorator(new House());
        decorator.door();
    }
}

三、工厂模式

工厂模式主要处理对象的多态,是开闭原则的一种实现,也就是可拓展 不可修改,工程模式有以下三类。

1.简单工厂

spring中bean的获取就是一种简单工厂模式,这里不过多赘述

2.工厂方法模式

和简单工厂的区别是简单工厂是一个工厂处理所有产品,工厂方法是多个工厂处理不通的产品

public interface IFactory {
    

    IProduct doProduct();
}
public interface IProduct {
    

    void execute();
}
public class IProductImplA implements IProduct {
    
    @Override
    public void execute() {
    
        System.out.println("产品A");
    }
}
public class IFactoryImplA implements IFactory{
    

    @Override
    public IProduct doProduct() {
    
        return new IProductImplA();
    }

    public static void main(String[] args){
    
        IFactory f = new IFactoryImplA();
        f.doProduct().execute();
    }
}

3.抽象工厂模式

抽象工厂模式和工厂方法模式相似,抽象工厂会抽象出一些具体行为,可以直观的看出工厂的功能。
如快递的物流公司选择。工厂中可以抽象出如下单 路由查询等具体行为。不同的物流公司的相同行为由不同的产品类实现,不同的工厂类只处理自家的业务。

四、建造模式

建造模式主要场景是对象的实例化或客户端的初始化。相比于构造函数的构造入参不可扩展,建造模式通过链式调用解决这一问题,对入参的一些校验可以放入build方法中,优势就是可扩展,可解耦。
实际应用的场景可以是调用第三方接口时生成入参,这种场景往往是通过本地的数据生成接口需要的入参。

import lombok.Data;

@Data
public class Good {
    

    private String name;

    private String price;

    public static class Builder {
    
        private String name;
        private String price;



        public Builder name(String name){
    
            this.name = name;
            return this;
        }

        public Builder price(String price){
    
            this.price = price;
            return this;
        }

        public Good build(){
    
            Good good = new Good();
            good.name = this.name;
            good.price = this.price;
            return good;
        }

    }
}
    public static void main(String[] args){
    
        Good good = new Good.Builder().name("1").price("2").build();
        System.out.println(good);
    }

五、适配器模式

顾名思义,购买了国外的电器,电压标准110V,而国内标准为220V,这时候需要一个电压转换器,适配器模式就是让本不兼容的事务可以使用。
拿上述举例,220V为适配者,110V为目标类

public class V220 {
    

    public void execute(){
    
        System.out.println("输出220V的电压");
    }
}
public interface Transform {
    

    /**
     * 负责电压转换
     */
    void transform();
}
/**
 * 110V电压转换器
 */
public class V110 implements Transform {
    

    private V220 v220;

    public V110(V220 v220) {
    
        this.v220 = v220;
    }

    @Override
    public void transform() {
    
        v220.execute();
        System.out.println("输出110V电压");
    }

    public static void main(String[] args){
    
        V110 v110 = new V110(new V220());
        v110.transform();
    }
}

适用对需要对输出结果进行转换的场景。

六、模板模式

模板是个人对一些流程化的 较复杂的业务常使用的设计模式,拿医疗系统的开立检查检验项目为例,业务流程大概是这么几块,创建就诊卡->科室挂号->项目申请,可能大部分人就是通过controller+接口实现进行开发,这种开发模式时间久了或者接手了别人的代码,这种流程性的行为就很难通过后端代码有一个直观的认识,往往需要通过前端代码确定整个接口流程。如果通过抽象类抽象公有行为,并设置流程模板,并且抽象类不同于接口,抽象类中可以提取并实现一些公有方法,对于后面的扩展是十分方便的。


/**
 * 检查检验申请抽象类
 */
@Data
public abstract class AbstractMedTecApply {
    

    //开立检查检验业务代码模板 获取病历号 + 挂号 + 申请
    public final void addMedicalTec() throws PBMException {
    
        init();
        checkApply();
        //挂号
        register();
        //申请
        apply();
    }

    /**
     * 申请前做一些校验
     */
    public void checkApply() throws PBMException {
    
        //校验就诊状态
    }

    //获取his病历号
    public void setPatientId(Map<String, Object> outPatientInfo) throws PBMException {
    
        //如果没有his病历号则调用接口获取
    }


    /**
     * 检查检验做各自的初始化
     */
    protected abstract void init();

    /**
     * 挂号 区分检验检查
     *
     * @throws PBMException
     */
    protected abstract void register() throws PBMException;

    /**
     * 医技申请
     *
     * @throws PBMException
     */
    protected abstract void apply() throws PBMException;

}

七、代理模式

代理模式的设计思路参考nginx的反向代理,客户类通过代理类调用委托类。
代理模式和装饰模式很像,说到区别网上有很多,但是我觉得还是参考nginx的反向代理,当调用的时候感知不到委托类的就是代理模式。
代理模式就不写代码了,无非就是隐藏委托类的代码。

八、责任链模式

使用链表的流程性场景,责任链模式中所有的对象都有一个共用的父类或接口,子类都调用的父类的同一个方法处理业务,子类间链式引用,最终通过父类方法处理多个子类。
下面的代码通过大家最熟悉的请假流程举例

package com.orange.demo.design.chain;

public abstract class Handler {
    

    // 最大请假天数
    public int maxDays;

    // 部门
    public String dept;

    public Handler(String dept, int maxDays){
    
        this.dept = dept;
        this.maxDays = maxDays;
    }

    private Handler nextHandler;

    public void next(Handler handler){
    
        this.nextHandler = handler;
    }

    /**
     * 请假天数校验
     * @param n 申请请假天数
     */
    public final void check(int n){
    
        if (this.maxDays>=n) {
    
            this.agree();
        } else {
    
            if (this.nextHandler!=null) {
    
                nextHandler.check(n);
            } else {
    
                System.out.println("审批不通过");
            }
        }
    }

    protected void agree(){
    
        System.out.println("部门 "+ this.dept + " 已同意");
    }
}

package com.orange.demo.design.chain;

public class DeptA extends Handler {
    

    public DeptA(String dept, int maxDays) {
    
        super(dept, maxDays);
    }
}

package com.orange.demo.design.chain;

public class DeptB extends Handler {
    

    public DeptB(String dept, int maxDays) {
    
        super(dept, maxDays);
    }
}

package com.orange.demo.design.chain;

public class DeptC extends Handler {
    
    public DeptC(String dept, int maxDays) {
    
        super(dept, maxDays);
    }
}

    public static void main(String[] args){
    
        DeptA a = new DeptA("研发部", 5);
        DeptB b = new DeptB("主管部", 10);
        DeptC c = new DeptC("董事局", 15);
        a.next(b);
        b.next(c);
        a.check(15);
    }

九、享元模式

享元模式的核心就是享,做到对象共亨,避免创建大量重复变量。
线程池,连接池,字符串常量池都是这类模式的运用。

十、观察者模式

类似消息队列的发布订阅模式,观察者相当于消费者的角色,多个观察者同时监听某一事件。

public interface Broker {
    

    void addObserver(Observer observer);

    void notify(String msg);
}

public class BrokerImpl implements Broker {
    

    private List<Observer> obsList = new ArrayList<>();

    @Override
    public void addObserver(Observer observer) {
    
        obsList.add(observer);
    }

    @Override
    public void notify(String msg) {
    
        for (Observer ob : obsList) {
    
            ob.getMsg(msg);
        }
    }
}

public class Observer {
    

    private String name;

    public Observer(String name) {
    
        this.name = name;
    }

    public void getMsg(String msg){
    
        System.out.println(name+"收到消息了 " + msg);
    }
}
    public static void main(String[] args){
    
        Observer a = new Observer("a");
        Observer b = new Observer("b");
        Broker broker = new BrokerImpl();
        broker.addObserver(a);
        broker.addObserver(b);
        broker.notify("xxxxxx");
    }

十一、策略模式

策略模式由抽象策略类 策略实现类 上下文类三部分组成,策略模式中通过上下文类实现策略。
乍看下和工厂模式很像,策略模式侧重对单个行为的算法的不同选择,工厂模式的范围比较大,是对多个行为封装到工厂后,再对行为进行实现。策略模式通过将策略实例传入上下文类中实现行为,工厂模式选择工厂后直接调用行为方法。
下面用多种支付方法举例

/**
 * 多种支付方式
 */
public interface PayStrategy {
    

    /**
     * 支付方式
     */
    void payWay();
}

/**
 * 支付宝
 */
public class AliStrategy implements PayStrategy {
    
    @Override
    public void payWay() {
    
        System.out.println("支付宝支付");
    }
}
/**
 * 微信
 */
public class WXPayStrategy implements PayStrategy {
    
    @Override
    public void payWay() {
    
        System.out.println("微信支付");
    }
}

public class PayContext {
    

    private PayStrategy payStrategy;

    public PayContext(PayStrategy payStrategy) {
    
        this.payStrategy = payStrategy;
    }

    public void pay(){
    
        payStrategy.payWay();
    }
}
    public static void main(String[] args){
    
        PayStrategy ali = new AliStrategy();
        PayContext context = new PayContext(ali);
        context.pay();
    }

总结

上面列举了部分设计模式,可以发现很多设计模式的思想都是相似的,就像张三丰教张无忌太极一样,设计模式是一种解决问题的思想,没有固定的套路。
快去使用设计模式吧!!!

to be continue…

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_16094131/article/details/132075754

智能推荐

while循环&CPU占用率高问题深入分析与解决方案_main函数使用while(1)循环cpu占用99-程序员宅基地

文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。​​​​​​while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99

【无标题】jetbrains idea shift f6不生效_idea shift +f6快捷键不生效-程序员宅基地

文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效

node.js学习笔记之Node中的核心模块_node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是-程序员宅基地

文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是

数学建模【SPSS 下载-安装、方差分析与回归分析的SPSS实现(软件概述、方差分析、回归分析)】_化工数学模型数据回归软件-程序员宅基地

文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件

利用hutool实现邮件发送功能_hutool发送邮件-程序员宅基地

文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件

docker安装elasticsearch,elasticsearch-head,kibana,ik分词器_docker安装kibana连接elasticsearch并且elasticsearch有密码-程序员宅基地

文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码

随便推点

Python 攻克移动开发失败!_beeware-程序员宅基地

文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware

Swift4.0_Timer 的基本使用_swift timer 暂停-程序员宅基地

文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停

元素三大等待-程序员宅基地

文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待

Java软件工程师职位分析_java岗位分析-程序员宅基地

文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析

Java:Unreachable code的解决方法_java unreachable code-程序员宅基地

文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code

标签data-*自定义属性值和根据data属性值查找对应标签_如何根据data-*属性获取对应的标签对象-程序员宅基地

文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象

推荐文章

热门文章

相关标签