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

智能推荐

分布式光纤传感器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告_预计2026年中国分布式传感器市场规模有多大-程序员宅基地

文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大

07_08 常用组合逻辑电路结构——为IC设计的延时估计铺垫_基4布斯算法代码-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码

OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版-程序员宅基地

文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版

关于美国计算机奥赛USACO,你想知道的都在这_usaco可以多次提交吗-程序员宅基地

文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗

MySQL存储过程和自定义函数_mysql自定义函数和存储过程-程序员宅基地

文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程

半导体基础知识与PN结_本征半导体电流为0-程序员宅基地

文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0

随便推点

【Unity3d Shader】水面和岩浆效果_unity 岩浆shader-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader

广义线性模型——Logistic回归模型(1)_广义线性回归模型-程序员宅基地

文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型

HTML+CSS大作业 环境网页设计与实现(垃圾分类) web前端开发技术 web课程设计 网页规划与设计_垃圾分类网页设计目标怎么写-程序员宅基地

文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写

C# .Net 发布后,把dll全部放在一个文件夹中,让软件目录更整洁_.net dll 全局目录-程序员宅基地

文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录

BRIEF特征点描述算法_breif description calculation 特征点-程序员宅基地

文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点

房屋租赁管理系统的设计和实现,SpringBoot计算机毕业设计论文_基于spring boot的房屋租赁系统论文-程序员宅基地

文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文