设计模式-相关内容

news2024/9/23 1:32:12

文章目录

  • 一、设计模式概述
  • 二、UML图
    • 1.类的表示方法
    • 2.类与类之间关系的表示方法
      • (1)关联关系
      • (2)聚合关系
      • (3)组合关系
      • (4)依赖关系
      • (5)继承关系
      • (6)实现关系
  • 三、软件设计原则
    • 1.开闭原则
    • 2.里氏代换原则
    • 3.依赖倒转原则
    • 4.接口隔离原则
    • 5.合成复用原则
    • 6.迪米特法则

一、设计模式概述

创建型模式:用于描述怎样创建对象,它的主要特点是将对象的创建与使用分离。
           有单例、原型、工厂方法、抽象工厂、创建者等5种

结构型模式:用于描述如何将类或对象按某种布局组成更大的结构。
          有代理、适配器、桥接、装饰、外观、享元、组合等7种

行为型模式:用于描述类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,
                     以及怎样分配职责。有模板方法、策略命令、职责链、状态、观察者、中介者、
                     迭代器、访问者、备忘录、解释器等11种

二、UML图

1.类的表示方法

在这里插入图片描述

包含 类名 属性 方法

+ :表示public
- :表示private
# :表示protected

2.类与类之间关系的表示方法

(1)关联关系

是对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系

单向关联

双向关联

自关联

(2)聚合关系

是关联关系的一种,是强关联关系,是整体和部分之间的关系

(3)组合关系

表示类之间的整体与部分关系,它是一种更强烈的聚合关系。整体对象可以控制部分对象的生命周期,
一旦整体对象不存在,部分对象也将不存在

(4)依赖关系

是一种使用关系,它是对象之间耦合度最弱的一种关联关系,是临时性的关联

在代码中,某个类的方法通过局部变量、方法的参数或者静态方法的调用来访问另一个类中的某些方法来
完成一些职责

(5)继承关系

继承关系是对象之间耦合度最大的一种关系,表示一般与特殊的关系,是父类与子类之间的关系
,是一种继承关系

(6)实现关系

实现关系是接口与实现类之间的关系

三、软件设计原则

1.开闭原则

对扩展开放,对修改关闭

对程序需要进行拓展的时候,不能去修改原来的代码,要想做到这样需要使用接口和抽象类
/**
 * 抽象皮肤类
 */
public abstract class AbstractSkin {

    //显示使用哪个皮肤
    public abstract void display();

}


/**
 * 默认皮肤类
 */
public class DefaultSkin extends AbstractSkin{

    @Override
    public void display() {
        System.out.println("默认皮肤");
    }
}


/**
 * 布布皮肤
 */
public class BuBuSkin extends AbstractSkin{

    @Override
    public void display() {
        System.out.println("这是布布的皮肤");
    }
}


/**
 * 输入法
 */
public class YiErInput {

    private AbstractSkin skin;

    public void setSkin(AbstractSkin skin) {
        this.skin = skin;
    }

    public void display(){
        skin.display();
    }
}


public class Client {

    public static void main(String[] args) {
        YiErInput input = new YiErInput();
        //AbstractSkin skin = new DefaultSkin();
        AbstractSkin skin = new BuBuSkin();
        input.setSkin(skin);
        input.display();
    }

}

2.里氏代换原则

任何基类可以出现的地方,子类一定可以出现

子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说子类继承父类时,
除添加新的方法完成新增功能外,尽量不要重写父类的方法

不复合里氏代换原则

/**
 * 长方形类
 */
public class Rectangle {

    private double length;
    private double width;

    public double getLength() {
        return length;
    }

    public void setLength(double length) {
        this.length = length;
    }

    public double getWidth() {
        return width;
    }

    public void setWidth(double width) {
        this.width = width;
    }
}


/**
 * 正方形类
 */
public class Square extends Rectangle{

    @Override
    public void setLength(double length) {
        super.setLength(length);
        super.setWidth(length);
    }

    @Override
    public void setWidth(double width) {
        super.setLength(width);
        super.setWidth(width);
    }
}


public class RectangleDemo {

    public static void main(String[] args) {
        //创建长方形对象
        Rectangle r = new Rectangle();
        r.setLength(10);
        r.setWidth(5);
        resize(r);
        printLengthAndWidth(r);

        System.out.println("===============");

        //创建正方形对象
        Rectangle s = new Square();
        s.setLength(10);//设置长和宽
        resize(s);
        printLengthAndWidth(s);
    }

    //扩宽方法
    public static void resize(Rectangle rectangle){
        //判断宽是否小于等于长,就进行扩宽
        while (rectangle.getWidth() <= rectangle.getLength()){
            rectangle.setWidth(rectangle.getWidth() + 1);
        }
    }

    //打印长和宽
    public static void printLengthAndWidth(Rectangle rectangle){
        System.out.println("长 : " + rectangle.getLength());
        System.out.println("宽 : " + rectangle.getWidth());
    }

}

符合里氏代换原则

public interface Quadrilateral {

    double getLength();//获取长

    double getWidth();//获取宽

}


/**
 * 正方形
 */
public class Square implements Quadrilateral{

    private double side;

    public double getSide() {
        return side;
    }

    public void setSide(double side) {
        this.side = side;
    }

    @Override
    public double getLength() {
        return side;
    }

    @Override
    public double getWidth() {
        return side;
    }
}


/**
 * 长方形类
 */
public class Rectangle implements Quadrilateral{

    private double length;
    private double width;

    public void setLength(double length) {
        this.length = length;
    }

    public void setWidth(double width) {
        this.width = width;
    }

    @Override
    public double getLength() {
        return length;
    }

    @Override
    public double getWidth() {
        return width;
    }
}


public class RectangleDemo {

    public static void main(String[] args) {
        //创建长方形对象
        Rectangle r = new Rectangle();
        r.setLength(10);
        r.setWidth(5);
        resize(r);
        printLengthAndWidth(r);

        System.out.println("===============");

        //创建正方形对象
        Square s = new Square();
        s.setSide(10);//设置长和宽
        printLengthAndWidth(s);
    }

    //扩宽方法
    public static void resize(Rectangle rectangle){
        //判断宽是否小于等于长,就进行扩宽
        while (rectangle.getWidth() <= rectangle.getLength()){
            rectangle.setWidth(rectangle.getWidth() + 1);
        }
    }

    //打印长和宽
    public static void printLengthAndWidth(Quadrilateral quadrilateral){
        System.out.println("长 : " + quadrilateral.getLength());
        System.out.println("宽 : " + quadrilateral.getWidth());
    }

}

3.依赖倒转原则

高层模块不应该依赖于底层模块,两者都应该依赖其抽象;抽象不应该依赖于细节,细节应该依赖于抽象。

简单来说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合
/**
 * 硬盘接口
 */
public interface HardDisk {

    //存储数据
    public void save(String data);

    //获取数据
    public String getData();
}

public class XiJieHardDisk implements HardDisk{

    @Override
    public void save(String data) {
        System.out.println("使用希捷硬盘存储数据为 : " + data);
    }

    @Override
    public String getData() {
        System.out.println("使用希捷硬盘获取数据");
        return "data";
    }
}


/**
 * cpu接口
 */
public interface Cpu {

    public void run();//运行

}

public class IntelCpu implements Cpu{

    @Override
    public void run() {
        System.out.println("使用intel处理器");
    }
}


/**
 * 内存条接口
 */
public interface Memory {

    public void save();

}

public class KingstonMemory implements Memory{

    @Override
    public void save() {
        System.out.println("使用金士顿内存条");
    }
}


public class Computer {

    private HardDisk hardDisk;
    private Cpu cpu;
    private Memory memory;

    public HardDisk getHardDisk() {
        return hardDisk;
    }

    public void setHardDisk(HardDisk hardDisk) {
        this.hardDisk = hardDisk;
    }

    public Cpu getCpu() {
        return cpu;
    }

    public void setCpu(Cpu cpu) {
        this.cpu = cpu;
    }

    public Memory getMemory() {
        return memory;
    }

    public void setMemory(Memory memory) {
        this.memory = memory;
    }

    //运行计算机
    public void run(){
        System.out.println("运行计算机");
        String data = hardDisk.getData();
        System.out.println("从硬盘上获取的数据是 : " + data);
        cpu.run();
        memory.save();
    }
}


public class ComputerDemo {

    public static void main(String[] args) {
        //创建计算机对象
        Computer computer = new Computer();

        //创建计算机的组件
        HardDisk hardDisk = new XiJieHardDisk();//硬盘
        Cpu cpu = new IntelCpu();//cpu
        Memory memory = new KingstonMemory();//内存条

        //组装
        computer.setHardDisk(hardDisk);
        computer.setCpu(cpu);
        computer.setMemory(memory);

        //运行
        computer.run();
    }

}

4.接口隔离原则

客户端不应该被迫依赖于它不使用的方法,一个类对另一个类的依赖应该建立在最小的接口上
/**
 * 防盗接口
 */
public interface AntiTheft {

    void antiTheft();

}

/**
 * 防火接口
 */
public interface Fireproof {

    void fireproof();

}

/**
 * 防水接口
 */
public interface Waterproof {

    void waterproof();

}

public class YourDoor implements AntiTheft,Fireproof,Waterproof{

    @Override
    public void antiTheft() {
        System.out.println("防盗");
    }

    @Override
    public void fireproof() {
        System.out.println("防火");
    }

    @Override
    public void waterproof() {
        System.out.println("防水");
    }
}

public class MyDoor implements Fireproof{

    @Override
    public void fireproof() {
        System.out.println("只能防火");
    }
}

public class DoorTest {

    public static void main(String[] args) {

        //创建安全门对象
        YourDoor yourDoor = new YourDoor();
        //功能
        yourDoor.antiTheft();
        yourDoor.fireproof();
        yourDoor.waterproof();

        System.out.println("---------------");

        MyDoor myDoor = new MyDoor();
        myDoor.fireproof();
    }

}

5.合成复用原则

尽量先使用组合或者聚合等关联关系来实现,其次才考虑继承关系来实现

通常类的复用分为继承复用和合成复用两种

继承复用简单易实现,但有以下缺点:
  1.破坏了类的封装性,因为继承会将父类的实现细节暴露给子类,父类对子类是透明的
  2.父类与子类的耦合度高,父类的实现的任何改变都会导致子类的实现发生变化,不宜与类的扩展与维护
  3.它限制了复用的灵活性,从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化
  
组合或聚合复用,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,
他有以下优点:
  1.它维持了类的封装性
  2.对象间的耦合度低,可以在类的成员位置声明为抽象
  3.复用的灵活性高,这种复用可以在运行时动态进行,新对象可以动态地引用与成员对象类型相同的对象

6.迪米特法则

如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。
其目的是降低类之间的耦合度,提高模块的相对独立性
/**
 * 明星类
 */
public class Star {

    private String name;

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

    public String getName() {
        return name;
    }
}

/**
 * 粉丝类
 */
public class Fans {

    private String name;

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

    public String getName() {
        return name;
    }
}

/**
 * 媒体公司类
 */
public class Company {

    private String name;

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

    public String getName() {
        return name;
    }
}

/**
 * 经纪人类
 */
public class Agent {

    private Star star;
    private Fans fans;
    private Company company;

    public void setStar(Star star) {
        this.star = star;
    }

    public void setFans(Fans fans) {
        this.fans = fans;
    }

    public void setCompany(Company company) {
        this.company = company;
    }

    //和粉丝见面
    public void meeting(){
        System.out.println(star.getName() + " 和粉丝 " + fans.getName() + " 见面");
    }

    //和媒体公司合作
    public void business(){
        System.out.println(star.getName() + " 和 " + company.getName() + "" + " 合作");
    }
}

public class Client {

    public static void main(String[] args) {
        //创建经纪人类
        Agent agent = new Agent();

        Star star = new Star("小红");
        Fans fans = new Fans("沙雕");
        Company company = new Company("巨坑人");

        agent.setStar(star);
        agent.setFans(fans);
        agent.setCompany(company);

        agent.meeting();
        agent.business();
    }

}

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

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

相关文章

集群分发脚本xysnc

一、scp&#xff08;secure copy&#xff09; 安全拷贝 1.定义 scp&#xff08;Secure Copy&#xff09;是一个用于在不同计算机之间安全地复制文件和目录的命令行工具。它使用 SSH 协议进行连接和文件传输&#xff0c;提供了加密和身份验证机制&#xff0c;确保数据传输的安…

Android 项目增加 res配置

main.res.srcDirs "src/main/res_test" build->android->sourceSets

从裸机启动开始运行一个C++程序(七)

前序文章请看&#xff1a; 从裸机启动开始运行一个C程序&#xff08;六&#xff09; 从裸机启动开始运行一个C程序&#xff08;五&#xff09; 从裸机启动开始运行一个C程序&#xff08;四&#xff09; 从裸机启动开始运行一个C程序&#xff08;三&#xff09; 从裸机启动开始运…

Mall脚手架总结(四) —— SpringBoot整合RabbitMQ实现超时订单处理

前言 在电商项目中&#xff0c;订单因为某种特殊情况被取消或者超时未支付都是比较常规的用户行为&#xff0c;而实现该功能我们就要借助消息中间件来为我们维护这么一个消息队列。在mall脚手架中选择了RabbitMQ消息中间件&#xff0c;接下来荔枝就会根据功能需求来梳理一下超时…

SRE实战:如何低成本推进风险治理?稳定性与架构优化的3个策略

一分钟精华速览 SRE 团队每天面临着不可控的各类风险和重复发生的琐事&#xff0c;故障时疲于奔命忙于救火。作为技术管理者&#xff0c;你一直担心这些琐事会像滚雪球一样&#xff0c;越来越多地、无止尽地消耗你的团队&#xff0c;进而思考如何系统性地枚举、掌控这些风险&a…

ctf中ping命令执行绕过

相关wp参考&#xff1a;CTF中的命令执行绕过方式 - 知乎 CTFping命令绕过及符号用法_ctf ping-CSDN博客 在用linux命令时候,我们可以 一行执行多条命令 或者 有条件的执行下一条命令 linux命令中一些符号的用法 1. “;”分号用法 方式&#xff1a;command1 ; command…

【ccf-csp题解】第7次csp认证-第三题-路径解析超详细题解-字符串模拟

本题思路来源于acwing ccfcsp认证课 题目描述 思路分析 首先&#xff0c;为了处理路径中的反斜杠符号&#xff0c;我们可以实现一个get函数&#xff0c;把一个路径中每一对反斜杠之间的内容存到vector<string>中&#xff0c;如果有连续的多个反斜杠则只看成一个 举个例…

“.NET视频总结:认识框架的结构和组件,掌握开发工具的奥妙“一

目录 第一单元&#xff1a;二十一世纪程序执行 背景: 总结&#xff1a; 第二单元:对象导向与类别设计 背景: 总结&#xff1a; 第三单元&#xff1a;使用类别与基底类别库 总结: 第四单元:Windows开发程序 背景: 总结: 第五单元:防护式程序设计 背景: 总结: 第六…

数据库中的DECODE函数,SIGN函数

oracle中的if(),oracle中if/else的三种实现方式详解_电竞GO的博客-CSDN博客 DECODE(CONCAT(b.AZZ231,%),%,,CONCAT(b.AZZ231,%)) czwcl,

Acrel-6000电气火灾监控系统应用

安科瑞 崔丽洁 摘要 建筑电气火灾在建筑物火灾中占较大的比例&#xff0c;起火原因也很多&#xff0c;包括短路、过热、漏电、雷击和电气等故障&#xff0c;火灾危害也较大。因此&#xff0c;各种原因引起的火灾都应得到有效控制。目前&#xff0c;短路、过热、雷击等保护措施…

【Java网络编程】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 Java是一种广泛应用于网络编程的编程语言。通过Java的网络编程能力&#xff0c;我们可以构建强大的网络应用程序。本文将介绍Java网络编程的基础知识、常用API和一些实…

nginx目录穿越

测试nginx版本为nginx/1.23.3 location /file {alias /home/;} 在/usr跟目录下新建a.txt测试文件 通过访问 http://{ip}:{端口}/file../test.txt 实现目录穿越 防护:location与alias的值都加上/或不加/

MongoDB实践

MongoDB学习 MongoDB简介 MongoDB 是一种流行的文档型 NoSQL 数据库&#xff0c;它具有以下特点和应用场景&#xff1a; 文档型数据库&#xff1a;MongoDB 使用 BSON&#xff08;Binary JSON&#xff09;格式的文档来存储数据。每个文档可以具有不同的字段&#xff0c;这使得…

山西电力市场日前价格预测【2023-10-12】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-10-12&#xff09;山西电力市场全天平均日前电价为506.23元/MWh。其中&#xff0c;最高日前电价为841.91元/MWh&#xff0c;预计出现在18: 30。最低日前电价为351.76元/MWh&#xff0c;预计…

关键词搜索速卖通商品列表接口,速卖通商品列表数据接口

在网页抓取方面&#xff0c;可以使用 Python、Java 等编程语言编写程序&#xff0c;通过模拟 HTTP 请求&#xff0c;获取速卖通网站上的商品页面。在数据提取方面&#xff0c;可以使用正则表达式、XPath 等方式从 HTML 代码中提取出有用的信息。值得注意的是&#xff0c;速卖通…

PowerDesinger导入保险业excel数据模型(代码亲测可用)

一、Excel表 按如下结构填充建表所需的数据(附 Excel 表模板): 二、PowerDesigner 新建模型 点击:File——>New Model——>Model types——>Physical Data Mode 三、PowerDesigner 导入 Excel 脚本 按住Ctrl+Shift+X进入脚本运行界面,导入以下脚本并运行: 注…

牛客 明明的随机数

HJ3 明明的随机数 原题思路代码运行截图收获 原题 HJ3 明明的随机数 思路 如果是C的话直接用set结构体就可以自动排序GO&#xff1a;用一个501的数组存储是否出现&#xff0c;最后从头开始输出出现过的数字 代码 #include <iostream> #include <set> using na…

css怎么实现文字描边

有时&#xff0c;我们会遇到UI稿有文字描边的效果&#xff0c;比如下图的效果。 一、给需要描边的文字加一个id选择器 例如&#xff1a; 二、css写法&#xff1a; number,{//这个是实现文字描边的关键&#xff0c;也就是‘空心文字’&#xff0c;这个是定义文字字符的描边的宽…

向量的运算

向量加法 实质是坐标加法。如下图&#xff1a; 向量减法 实质是坐标减法。如下图&#xff1a; 向量乘法 分为点乘和叉乘&#xff0c;点乘是计算平行四边形的面积&#xff0c;叉乘是计算投影&#xff0c;点乘为标量&#xff0c;叉乘为向量。

Git 使用技巧:5个提高效率的命令,不再只会pull和push

前言 使用 Git 作为代码版本管理&#xff0c;早已是现在开发工程师必备的技能。可大多数工程师还是只会最基本的保存、拉取、推送&#xff0c;遇到一些commit管理的问题就束手无策&#xff0c;或者用一些不优雅的方式解决。 本文分享我在开发工作中实践过的实用命令。这些都能…