精简:设计模式

news2024/9/25 13:23:58

1.设计模式概述

1.什么是设计模式

设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。
它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。

1995年,GoF (Gang of Four,四人组/四人帮)合作出版了《设计模式:可复用面向对象软件的基础》一书,共收录了23种设计模式,从此树立了软件设计模式领域的里程碑,人称「GoF设计模式」

2.学习设计模式的意义

设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。

  • 正确使用设计模式具有以下优点:
    • 可以提高程序员的思维能力、编程能力和设计能力。
    • 使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
    • 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。

3.23种设计模式

按照设计模式的作用可分为三种模式,创建型模式、结构型模式、行为型模式

设计模式类型设计模式
创建型模式单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式
结构型模式适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式
行为型模式模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式

4.七大设计原则

七大原则解释
开闭原则对扩展开放,对修改关闭
里氏替换原则在继承关系中子类可以拓展方法,不能修改父类原有方法的功能,降低需求变更带来的风险
依赖倒置原则要面向接口编程,不要面向实现编程。高层模块不直接依赖低层模块,二者依赖其抽象
单一职责原则控制类的粒度大小、将对象解耦、提高其内聚性。对于类/接口/方法,负责的功能单一
接口隔离原则不使用单一的总接口 使用多个专门职责的接口,接口间产生隔离
迪米特法则只与你的直接朋友交谈,不跟"陌生人”说话。其中一个类需要调用另一类的某一个方法的话,可以通过第三者转发这个调用。降低类与类之间的耦合
合成复用原则尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

2.创建者模式

1.单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问

主要解决:一个全局使用的类频繁地创建与销毁。

关键代码:构造函数是私有的,自己创建自己的唯一实例,公有的静态的方法

优点:

  • 1.在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
  • 2、避免对资源的多重占用(比如写文件操作)。

缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

应用场景:WEB 中的计数器

饿汉式

一上来就把所有的东西加载进来,非常浪费空间

类加载时创建(不管使不使用都创建),天生线程安全

生命周期长

/**
 * 饿汉式单例
 */
public class Hungry {
 
    /**
     * 可能会浪费空间
     */
    private byte[] data1=new byte[1024*1024];
    private byte[] data2=new byte[1024*1024];
    private byte[] data3=new byte[1024*1024];
    private byte[] data4=new byte[1024*1024];
 
 
 
    private Hungry(){
 
    }
    private final static Hungry hungry = new Hungry();
 
    public static Hungry getInstance(){
        return hungry;
    }
 
}

懒汉式

第一次调用才初始化,避免内存浪费。

单线程安全,多线程不安全

生命周期短

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
  
    public static Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

这里可以给他加锁完成线程安全,但是就降低了效率

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

DCL懒汉式(双重校验(判定)锁)

这里new对象的时候会有原子性不一致的问题,就导致可能出现指令重排的问题,给LazyMan2的类对象加一个volatile保证指令重排的问题

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
            if (singleton == null) {  
                singleton = new Singleton();  
            }  
        }  
    }  
    return singleton;  
    }  
}

静态内部类

线程安全,功能和双重校验锁一样

public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
    }  
}

但是这时候出现了问题,反射可以破坏单例模式

枚举

它更简洁,自动支持序列化机制,绝对防止多次实例化。可以防止反射来破坏单例模式,因为反射破坏不了枚举类

public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}

2.工厂模式

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象

  • 三种模式:
    • 简单工厂模式
      • 用来生产同一等级结构中的任意产品(对于增加新的产品,需要扩展已有代码)
    • 工厂方法模式
      • 用来生产同一等级结构中的固定产品(支持增加任意产品)
    • 抽象工厂模式
      • 围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。
  • 小结:
    • 简单工厂模式(静态工厂模式)
      • 虽然某种程度上不符合设计原则,但实际使用最多!
    • 工厂方法模式
      • 不修改已有类的前提下,通过增加新的工厂类实现扩展。
    • 抽象工厂模式
      • 不可以增加产品,可以增加产品族!

应用场景:JDBC中的Connection对象的获取、Spring中IOC容器创建管理bean对象、反射中Class对象的newInstance方法

简单工厂模式(静态工厂模式)

public interface Car {
    void name();
}

class Wuling implements Car {
    @Override
    public void name() {
        System.out.println("五菱");
    }
}

class Tesla implements Car {
    @Override
    public void name() {
        System.out.println("特斯拉");
    }
}

class CarFactory {
    public static Car getCar(String car) {
        if ("五菱".equals(car)) {
            return new Wuling();
        } else if ("特斯拉".equals(car)) {
            return new Tesla();
        } else {
            return null;
        }
    }
}

class Consumer {
    public static void main(String[] args) {
        //传统方式
        //Car wuling = new Wuling();
        //Car tesla = new Tesla();

        //工厂模式
        Car car = CarFactory.getCar("五菱");
        Car car1 = CarFactory.getCar("特斯拉");
        car.name();
        car1.name();

    }
}

这时我想要在加一辆车,那么车工厂就要增加一个大众类型的车,按照类型去寻找车

工厂方法

工厂方法,增加一层工厂的约束,对工厂去管理,要什么车就去什么工厂,然后工厂帮你找到车

public interface Car {
    void name();
}

class Wuling implements Car {
    @Override
    public void name() {
        System.out.println("五菱");
    }
}

class Tesla implements Car {
    @Override
    public void name() {
        System.out.println("特斯拉");
    }
}
interface CarFactory{
    Car getCar();
}
class TeslaFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new Tesla();
    }
}
class WulingFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new Wuling();
    }
}

class Consumer {
    public static void main(String[] args) {
        //传统方式
        //Car wuling = new Wuling();
        //Car tesla = new Tesla();

        //工厂模式
        //Car car = CarFactory.getCar("五菱");
        //Car car1 = CarFactory.getCar("特斯拉");
        //car.name();
        //car1.name();

        Car car = new WulingFactory().getCar();
        Car car1 = new TeslaFactory().getCar();
        car1.name();
        car.name();
    }
}

3.抽象工厂模式

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品

优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象

缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。

注意事项:产品族难扩展,产品等级易扩展。

//手机接口
public interface IphoneProduct {
    void start();
    void shutdown();
    void callup();
    void sendSMS();
}
//路由器接口
public interface IRouterProduct {
    void start();
    void shutdown();
    void openwife();
    void setting();
}

//华为手机
public class HuaweiPhone implements IphoneProduct{
    @Override
    public void start() {
        System.out.println("华为手机开机");
    }

    @Override
    public void shutdown() {
        System.out.println("华为手机关机");
    }

    @Override
    public void callup() {
        System.out.println("华为手机打电话");
    }

    @Override
    public void sendSMS() {
        System.out.println("华为手机发短信");
    }
}
//华为路由器
public class HuaweiRouter implements IRouterProduct{
    @Override
    public void start() {
        System.out.println("开启华为路由器");
    }

    @Override
    public void shutdown() {
        System.out.println("关闭华为路由器");
    }

    @Override
    public void openwife() {
        System.out.println("开启华为wifi");
    }

    @Override
    public void setting() {
        System.out.println("打开华为设置");
    }
}
//小米手机
public class XiaomiPhone implements IphoneProduct{

    @Override
    public void shutdown() {
        System.out.println("关闭小米手机");
    }

    @Override
    public void callup() {
        System.out.println("小米手机打电话");
    }

    @Override
    public void sendSMS() {
        System.out.println("小米手机发短信");
    }

    @Override
    public void start() {
        System.out.println("开启小米手机");
    }
}
//小米路由器
public class XiaomiRouter implements IRouterProduct{

    @Override
    public void start() {
        System.out.println("开启小米路由器");
    }

    @Override
    public void shutdown() {
        System.out.println("关闭小米路由器");
    }

    @Override
    public void openwife() {
        System.out.println("开启小米wifi");
    }

    @Override
    public void setting() {
        System.out.println("开启小米设置");
    }
}

//生产路由器和手机的工厂
public interface IProductFactory {
    //生产手机
    IphoneProduct iphoneProduct();
    //生产路由器
    IRouterProduct irouterproduct();
}

//生产华为系列路由器和手机的工厂
public class HuaweiFactory implements IProductFactory{
    @Override
    public IphoneProduct iphoneProduct() {
        return new HuaweiPhone();
    }

    @Override
    public IRouterProduct irouterproduct() {
        return new HuaweiRouter();
    }
}
//生产小米系列路由器和手机的工厂
public class XiaomiFactory implements IProductFactory{
    @Override
    public IphoneProduct iphoneProduct() {
        return new XiaomiPhone();
    }

    @Override
    public IRouterProduct irouterproduct() {
        return new XiaomiRouter();
    }
}

//主机,去找一个商品直接去该系列的工厂去寻找并使用
public class Clinet {
    public static void main(String[] args) {
        System.out.println("==========小米系列产品==========");
        //小米工厂
        XiaomiFactory xiaomiFactory = new XiaomiFactory();
        IphoneProduct iphoneProduct = xiaomiFactory.iphoneProduct();
        iphoneProduct.start();
        iphoneProduct.shutdown();
        System.out.println("==========华为系列产品==========");
        //小米工厂
        HuaweiFactory huaweiFactory = new HuaweiFactory();
        iphoneProduct = huaweiFactory.iphoneProduct();
        iphoneProduct.start();
        iphoneProduct.shutdown();


    }
}

4.建造者模式

将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。

与工厂模式的区别是:建造者模式更加关注与零件装配的顺序

优点: 1、建造者独立,易扩展。 2、便于控制细节风险。

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。

  • 建造者与抽象工厂模式的比较:
    • 与抽象工厂 模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族。
    • 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一 个复杂对象, 返回一个完整的对象。
    • 如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车!


public abstract class Builder {
    abstract void builderA();//地基
    abstract void builderB();//钢筋水泥
    abstract void builderC();//铺电线
    abstract void builderD();//粉刷

    //完工:得到产品
    abstract Product getproduct();
}

//产品:房子
public class Product {
    private String builderA;
    private String builderB;
    private String builderC;
    private String builderD;

//get set tostring
}

//具体建造者:工人
public class Worker extends Builder{
    private Product product;

    public Worker() {
        product = new Product();
    }

    @Override
    void builderA() {
        product.setBuilderA("地基");
        System.out.println("地基");
    }

    @Override
    void builderB() {
        product.setBuilderB("钢筋水泥");
        System.out.println("钢筋水泥");
    }

    @Override
    void builderC() {
        product.setBuilderC("铺电线");
        System.out.println("铺电线");
    }

    @Override
    void builderD() {
        product.setBuilderD("粉刷");
        System.out.println("粉刷");
    }

    @Override
    Product getproduct() {
        return product;
    }
}

//指挥:核心。负责构建一个工程,工程如何构建,由他决定。
public class Director {
    //指挥工人按照顺序建房子
    public Product build(Builder builder){
        builder.builderA();
        builder.builderB();
        builder.builderD();
        builder.builderC();

        return builder.getproduct();
    }
}

public class Test {
    public static void main(String[] args) {
        Director director = new Director();
        Product build = director.build(new Worker());
        System.out.println(build);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/399847.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

flutter工程创建过程中遇到一些问题。

安装环境版本:JDK7.-JDK 8 Andriod SDK 10 flutter 版本 3.0 1.当创建完后flutter工程后会遇到 run gradle task assemlble Debug 的问题,需要设置远程仓库,共需要修改三个地方build.gradle两处以及flutter 下面的D:\FVM\versions\3.0.0\pac…

Excel常用可视化图表

目录柱状图与条形图折线图饼图漏斗图雷达图瀑布图及甘特图旭日图组合图excel图表:柱状数据条、excel热力图、mini图可视化工具的表现形式:看板、可视化大屏、驾驶舱 柱状图与条形图 条形图是柱状图的转置 类别: 单一柱状图:反映…

Linux内核移植

内核移植半导体厂商会从linux内核官网下载某个版本,将其移植到自己的CPU上,测试成功后就会将其开放给该半导体的厂商的CPU开发者,开发者下载其提供的linux内核,然后将其移植到自己的 产品上。1、NXP官方开发板Linux内核编译测试编…

VR会议不断升级,为商务会谈打造云端洽谈服务!

VR会议不断升级,为商务会谈打造云端洽谈服务。在商务合作中,对客户需求的理解以及与客户讲解方案都需要建立在一个有效的沟通上,因此VR会议的用武之地就有了,以VR全景技术为核心,通过同屏互动和全景通信技术&#xff0…

wiki(维基)是什么?企业为什么需要搭建wiki?

维基百科是wiki的一个著名例子。维基百科上的内容可以由任何人创建和编辑,只要他们能够访问网络浏览器,并且可以使用简化的加价语言进行写作。对于 wiki,没有集中的作者或团队负责内容生成。从某种意义上说,维基是非常民主的。维基…

【SCL】移位和循环指令的应用(音乐喷泉改进)

移位指令:右移(SHR)左移(SHL)和循环左移/右移(ROR/ROL)指令的应用 文章目录 目录 一、移位和循环移位指令 1.左移右移 2.使用左移和脉冲实现音乐喷泉 3.循环移位指令 二、优化的其它方法 1.使用…

计算机SCI期刊的分值是什么意思? - 易智编译EaseEditing

影响因子(Impact Factor,IF)是美国ISI(科学信息研究所)的JCR(期刊引证报告)中的一项数据。 即某期刊前两年发表的论文在统计当年的被引用总次数除以该期刊在前两年内发表的论文总数。这是一个国际上通行的期刊评价指标。 例如,某期刊2005年影…

2023年主流的固定资产管理方式

2023年主流的固定资产管理方式可能有以下三种: 基于PaaS平台的固定资产管理系统,支持低代码平台,可以通过拖拉拽的方式进行表单搭建、流程搭建、自定义仪表盘等,满足不同行业和企业的个性化需求。基于RFID和二维码相结合的固定资…

卷麻了,00后Jmeter用的比我还熟练,简直没脸见人......

经常看到无论是刚入职场的新人,还是工作了一段时间的老人,都会对测试工具的使用感到困扰?前言性能测试是一个全栈工程师/架构师必会的技能之一,只有学会性能测试,才能根据得到的测试报告进行分析,找到系统性…

Allegro如何快速查看差分对是否等长的方法

在用Allegro进行PCB设计时,用快速查看差分对是否等长的方法,可以提高效率。那如何操作呢?具体操作方法如下:(1)选择菜单栏Route选择Timing Vision(时序视图) 然后在Options选项卡Tim…

陀螺和加计有关参数部分说明

部分参数计算一、零偏二、随机游走三、Allan方差分析使用要点一、零偏 如果只用一个指标来代表一款IMU的精度的话,那毫无疑问是陀螺零偏。这是因为:1) 惯导系统的精度主要取决于IMU中的陀螺器件精度,而不是加速度计精度;2) 陀螺的…

黑客入门教程【非常详细】从零基础入门到精通,看这一篇就够了!

首先要明白啊,我们现在说的黑客不是那种窃取别人信息、攻击别人系统的黑客,说的是调试和分析计算机安全系统的网络安全工程师。 黑客技术的核心就是渗透攻防技术,是为了证明网络防御按照预期计划正常运行而提供的一种机制。就是通过模拟恶意…

C#:Krypton控件使用方法详解(第十三讲) ——kryptonDomainUpDown

今天介绍的Krypton控件中的kryptonDomainUpDown。下面介绍控件的外观属性和Item属性:Cursor属性:表示鼠标移动过该控件的时候,鼠标显示的形状。属性值如下图所示:Text属性:表示控件的显示文本内容,属性值为…

Apache HTTP Server <2.4.56 mod_proxy_uwsgi 模块存在请求走私漏洞(CVE-2023-27522)

漏洞描述 Apache HTTP Server 是一个Web服务器软件。 该项目受影响版本存在请求走私漏洞。由于mod_proxy_uwsgi.c 中uwsgi_response方法对于源响应头缺少检查,当apache启用mod_proxy_uwsgi后,攻击者可利用过长的源响应头等迫使应转发到客户端的响应被截…

单例模式(设计模式详解)

单例模式 描述 单例模式是一种创建型模式,它的目的是确保一个类只有一个实例,并提供全局访问点。这个实例可以被多个客户端共享,从而避免创建多个实例所带来的资源浪费和不必要的复杂性。 实现 懒汉模式 public class LasySingleton {priv…

数以千计的网站使用的FTP凭证被劫持

云安全初创公司 Wiz 警告说,一场广泛的重定向活动已经导致数千个针对东亚受众的网站使用合法的 FTP 凭据遭到破坏。 在许多情况下,攻击者设法获得高度安全的自动生成的 FTP 凭据,并使用它们劫持受害网站,将访问者重定向到成人主题…

[学习笔记] 3. 算法进阶

算法进阶视频地址:https://www.bilibili.com/video/BV1uA411N7c5 1. 贪心算法 贪心算法(又称贪婪算法),是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑 —— 所做…

java零基础入门(1)

java零基础入门一、JRE和JDK1.1 JRE1.2 JDK1.3 IDK,JRE,JVM三者的包含关系二、CMD2.1 打开CMD2.2 常用CMD命令2.2.1 盘符名称 冒号2.2.2 dir2.2.3 cd 目录2.2.4 cd ..2.2.5 cls2.2.6 exit2.2.7 cd \2.2.8 cd \目录\目录\目录\目录2.3 利用快捷cmd打开 Q…

泰山众筹电商模式的分析

泰山众筹模式是电商平台营销玩法,市场上高活跃度的现象也证实了众筹模式的口碑,结合社交电商的模型,会员和产品销量都会得到飞跃,并且这样结合以后,泰山众筹模式也会更长久、合理,以及可持续。 泰山众筹模…

传输层——TCP协议

目录 一.TCP协议介绍 1.1简介 1.2TCP协议格式 32位序号/32位确认号 标志位 1.3tcp的发送和接收缓冲区 1.3.1介绍 1.3.2窗口大小 1.4超时重传 二.连接管理 2.1三次握手 2.2三次握手的状态变化 2.3为什么是三次握手? 2.4套接字与三次握手关系 2.5四次挥手…