软件设计建模与重构知识点

软件设计建模与重构知识点

前言

这篇文章主要介绍软件设计建模与重构


一、软件建模

软件设计建模与重构主要分一下几个方面:

1、需求分析 2、基础设计模式 3、特征威胁分析方法 4、身份与访问管理安全设计 5、故障模式分析方法 6、软件建模 7、设计模式应用 8、重构分析与方法

组合>聚合>关联>依赖。

类图中的6大关系_类图的六种关系-CSDN博客

2024年10月16日17:13:02
另外一种关系是泛化 = 实现 > 组合/合成 > 聚合 > 关联 > 依赖
类图中六种关系

用例图中的include关系是对应UML四种关系中的(依赖)

二、ilearning推荐入口

链接:

如何学习设计模式? - 知乎

三、对象组合

1、对象组合介绍

帖子:Java初学 对象组合及调用_java对象组合-CSDN博客

四、接口的概念

1、c++中接口的概念

以下是帖子中对接口的介绍


在C++中,接口(Interface)是一种抽象的概念,用于定义类或模块对外提供的操作、方法或功能的集合。接口规定了类或模块的公共契约,描述了其可用的方法和属性,而不涉及具体的实现细节。

在C++中,接口可以通过抽象类(Abstract Class)和纯虚函数(Pure Virtual Function)来实现。

抽象类是一个包含至少一个纯虚函数的类,无法直接实例化,只能作为基类使用。抽象类用于定义接口,规定了派生类必须实现的方法。派生类必须实现基类的纯虚函数才能被实例化。抽象类中可以包含非纯虚函数和成员变量。

以下是一个抽象类的示例:

class AbstractShape {
public:
    virtual void draw() = 0;   // 纯虚函数,定义了接口
    virtual double area() = 0; // 纯虚函数,定义了接口
 
    void printName() {
        std::cout << "Abstract Shape" << std::endl;
    }
};
 
class Circle : public AbstractShape {
public:
    void draw() override {
        std::cout << "Drawing a circle." << std::endl;
    }
 
    double area() override {
        // 计算圆的面积
    }
};
 
class Rectangle : public AbstractShape {
public:
    void draw() override {
        std::cout << "Drawing a rectangle." << std::endl;
    }
 
    double area() override {
        // 计算矩形的面积
    }
};

在上述示例中,AbstractShape 是一个抽象类,包含了纯虚函数 draw()area(),定义了图形类的接口。派生类 CircleRectangle 必须实现这两个纯虚函数才能被实例化。

纯虚函数通过在声明末尾添加 = 0 来标记,它们没有默认的实现,只提供了接口的定义。任何包含纯虚函数的类都被认为是抽象类,不能直接实例化,只能作为基类使用。

接口的使用可以实现多态性,使得不同的类可以使用相同的接口来进行操作,增强了代码的灵活性、可扩展性和可维护性。
c++接口_TenSun2023的博客-CSDN博客

2、java

java中接口有interface说明。

五、extends和implements

extends和implements的概念和区别

翻译:extends翻译延伸 implements翻译实施

1、Java的extends(继承)与implements(接口)

百度安全验证

2、c++

C++中用 :extends来表示继承关系。

c++中好像没有implements这个关键字。

这个帖子里有介绍final和this的用法,还介绍了c++的struct和class。

还介绍了override的用法:【override 关键字是 C++11 引入的,用来在派生类中成员函数声明时明确表明需要派生类去重写的那些成员方法,这样如果程序员在成员方法实体定义中做的不对编译器可以报错提醒】

C++学习笔记9 - 类与面向对象中的关键字_c++面向对象关键字__Amen的博客-CSDN博客

这个帖子介绍了子类和基类的兼容性规则:

c++:继承(1)_c++ extends-CSDN博客

1、派生类的对象可以赋值给基类的对象。

2、派生类对象的地址可以赋值给其基类的指针变量

3、派生类对象可以初始化基类的引用

六、super

这个帖子介绍了super的用法

言简意赅:由于子类不能继承父类的构造方法,因此,如果要调用父类的构造方法,可以使用 super 关键字。super 可以用来访问父类的构造方法、普通方法和属性。

super 关键字的用法:

super.父类属性名:调用父类中的属性
super.父类方法名:调用父类中的方法
super():调用父类的无参构造方法
super(参数):调用父类的有参构造方法

面向对象(下)④_c++ 子类比父类多一些职能_晓辰&的博客-CSDN博客

2023年12月13日11:53:12

c++不支持super,c++支持多继承,所以如果c++支持super,super无法确定究竟是来自于哪一个父类的同名方法。

C++有super关键字么?-CSDN博客

七、23种设计模式

7.1装饰模式

这个帖子里的代码亲测可行

package decorator;
import java.awt.*;
import javax.swing.*;
public class MorriganAensland
{
    public static void main(String[] args)
    {
        Morrigan m0=new original();
        m0.display();
        Morrigan m1=new Succubus(m0);
        m1.display();
        Morrigan m2=new Girl(m0);
        m2.display();
    }
}
//抽象构件角色:莫莉卡
interface  Morrigan
{
    public void display();
}
//具体构件角色:原身
class original extends JFrame implements Morrigan
{
    private static final long serialVersionUID = 1L;
    private String t="Morrigan0.jpg";
    public original()
    {
        super("《恶魔战士》中的莫莉卡·安斯兰");
    }
    public void setImage(String t)
    {
        this.t=t;
    }
    public void display()
    {
        this.setLayout(new FlowLayout());
        JLabel l1=new JLabel(new ImageIcon("src/decorator/"+t));
        this.add(l1);
        this.pack();
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}
//抽象装饰角色:变形
class Changer implements Morrigan
{
    Morrigan m;
    public Changer(Morrigan m)
    {
        this.m=m;
    }
    public void display()
    {
        m.display();
    }
}
//具体装饰角色:女妖
class Succubus extends Changer
{
    public Succubus(Morrigan m)
    {
        super(m);
    }
    public void display()
    {
        setChanger();
        super.display();
    }
    public void setChanger()
    {
        ((original) super.m).setImage("Morrigan1.jpg");
    }
}
//具体装饰角色:少女
class Girl extends Changer
{
    public Girl(Morrigan m)
    {
        super(m);
    }
    public void display()
    {
        setChanger();
        super.display();
    }
    public void setChanger()
    {
        ((original) super.m).setImage("Morrigan2.jpg");
    }
}

IDEA file-new-project创建无框架的java工程,在src创建package名为decorator的包,在该package创建java文件,即将代码粘贴到java文件中,同时将下载的三个图片放在MorriganAensland.java同级目录下,点击运行,则显示茉莉卡三个图片,成功!

装饰模式(Decorator模式)详解-CSDN博客


2023年10月19日11:25:00总结以上,上面的其实的源头是查牛客题目上的装饰模式,然后牵扯出一大片,害,确实有收获啊,因为一个点牵扯出那么多的知识点,很多还是自己之前一直很难理解的东西,比如super。

以前都不明白别人是怎么能写那么大一个工程,现在才慢慢开始理解,因为他们用的设计模式,先整理好架构才写的大工程。

7.2访问者模式

访问者模式看了这个帖子:23种设计模式之访问者模式(Visitor Pattern)-CSDN博客

7.3观察者模式

牛客网公司真题_免费模拟题库_企业面试|笔试真题

这次做的这个题目,观察者模式遇到了好几次,比如这个题目

题目一、假设猫是老鼠和狗的观察目标,老鼠和狗是观察者,猫叫老鼠跑,狗也跟着叫,可以使用( )描述该过程。答案B。

A、命令模式

B、观察者模式

C、责任链

D、单例模式

解释:当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。

题目二、

对象间存在一对多关系,当一个对象被修改时,则会自动通知它的依赖对象,采用以下哪种设计模式最好?答案B。

A、建造者模式

B、观察者模式

C、策略模式

D、代理模式

解释:观察者模式是常用设计模式中的一种。在此种一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。 观察者设计模式定义了对象间的一种一对多的组合关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新
所以在今天主要研究一下观察者模式

评论区有这样两个链接:

大话设计模式-观察者模式
https://localhost.blog.csdn.net/article/details/89334733

大话设计模式-系列文章(共50篇):
https://blog.csdn.net/qq_41113081/category_8723350.html

上面那个观察者模式看了一下,好像有点看懂了。就是存在一对多的关系,一个发生变化,其他的观察者就会变化。其中的UML图对应程序好像也看懂了一些。

7.4 命令模式

c++版本:C++设计模式之——命令模式_c++命令模式-CSDN博客

八、常见九种UML图

https://www.cnblogs.com/hzxll/p/16190230.html

九、类图的六种关系

类图中的6大关系_类图的六种关系-CSDN博客

UML简介与类图详解 - 知乎

UML类图符号:各种关系说明以及举例_uml关系符号-CSDN博客

其中第二个帖子有个图挺好的

img

自己的总结;

1、组合与聚合

组合是不能分开的,比如人和心脏,人不能离开心脏。用实心菱形表示。实心菱形指向人。

聚合是可以分开的,比如雁群和大雁,大雁离开雁群还可以独立存在。用空心菱形表示。空心菱形指向雁群。

2、依赖和关联

依赖是A类用到了B类。A类依赖于B类。比如动物A类需要依赖水B类。用虚线箭头表示依赖。箭头指向子类、B类。

关联是A类和B类的结构关系。帖子中用企鹅和气候打比方。用实现箭头表示。箭头指向被关联的一方。

十、代码坏味道

10.1依恋情节

原理:

感觉这个帖子对依恋情节的解释会比较好懂。

某个函数为了实现其功能,经常从另一个类中获取大量数据。比起自身所在的类来说,更加依赖另一个类。

简单易懂读《重构》 - Feature Envy (依恋情结)_依恋情结 重构-CSDN博客

实例

如下代码存在什么坏代码味道?答案A

class User {
private:
ContactInfo contactInfo;
public:
void GetUserAddress(Address& address)
{
address.Country = contactInfo.GetCountry();
address.City = contactInfo.GetCity();
address.Street = contactInfo.GetStreet();
address.Community = contactInfo.GetCommunity();
address.Building = contactInfo.GetBuilding();
address.Floor = contactInfo.GetFloor();
}
};

img

答案:

A、依恋情结(feature envy)

B、数据泥团(Data Clumps)

C、中间人(Middle man)

D、狎昵关系/内幕交易

在备考代码重构的时候,完善了上面的题目。然后就是针对上面的几个选型,自己又去查了下其他几个选型是什么意思。首先查的就是B选型,数据泥团。但是并不好查相关资料,最后只查到一个相对好的资料。链接如下:代码重构(二)25种代码优化示例_代码重构例子-CSDN博客

然后根据上面链接所述的内容,总结下面几点:

10.2 数据泥团

数据项就像小孩子,喜欢成群结队地呆在一块。如果一些数据项总是一起出现的,并且一起出现更有意义的,就可以考虑,按数据的业务含义来封装成数据对象。反例如下:


public class User {

    private String firstName;
    private String lastName;

    private String province;
    private String city;
    private String area;
    private String street;
}
正例:

public class User {

    private UserName username;
    private Adress adress;
}

class UserName{
    private String firstName;
    private String lastName;
}
class Address{
    private String province;
    private String city;
    private String area;
    private String street;
}

10.3 异曲同工的类

**异曲同工的类**‌指的是两个或多个类在功能或属性上有很大的相似性,尽管它们可能由不同的开发人员编写,或者在不同的时间点创建,但它们实现了类似的功能或目的。这种相似性可能是由于业务需求、系统设计或开发过程中的某些疏忽导致的。这类问题通常出现在大型软件项目中,其中不同的开发团队可能独立地解决了相同的问题,或者在不同的模块中实现了相似的功能,而没有进行有效的沟通和共享信息。

A类的接口a,和B类的接口b,做的的是相同一件事,或者类似的事情。就把A和B叫做异曲同工的类。

十一、重构手法

11.1 函数搬移手法

看一个题目就能解释这个方法

函数搬移(Move Method/Move Function)是代码重构的一个重要方法,下列重构使用了函数搬移手法的是(C )

A、从类A派生出子类B和C,在类B和C中均有ChangeName的操作,将ChangeName提取到类A中。

B、将类A中的接口InterfaceA和InterfaceB搬移到一个单独的新类B中。

C、当发现类A某个函数不仅仅适用于当前类,还适用于其它的类时,将该函数抽取为独立函数放入工具类中,供其他类使用。

D、类A和类B均对同一对象做相同的设置操作,通过提取一个基类消除这部分重复的数据及其相关操作。

什么是函数搬移:

查了资料如下:

搬移函数(Move Method)

你的程序中,有个函数与其所驻类之外的另一个类进行更多的交流:调用后者,或者被后者调用。在该函数最常引用的类中建立一个有着类似行为的新函数。将就函数变成一个单纯的委托函数,或是将旧函数完全移除

一、动机

减少类之间的耦合,是系统中的类更简单,更干净利落的完成系统交付的任务

二、做法

1、检查源类中被原函数所使用的一切特性,考虑它们是否也应该被搬移。考虑是否要将使用相同特性的函数一并搬移

2、检查源类的超类和子类,看看是否有该函数的其他声明

3、在目标类中声明这个函数

4、将原函数代码复制到目标函数中。调整后者,使其在新家中能够正常运行

5、编译目标类

6、决定如何从源函数正确的引用目标对象

7、修改源函数,使之成为一个纯委托函数

8、编译测试

9、决定是否删除源函数,或将它当做一个委托函数保留下来

10、如果要移除源函数,请将源类中对函数的所有调用,替换为对目标函数的调用

11、编译,测试

十二、题目

1、题目1

(多选题)针对重构方法,下列说法错误的有( ABD )

A、提取接口(Extract Interface)和提取超类(Extract Superclass)均可提取共通代码

B、隐藏委托关系(Hide Delegate)会使代码层次更清晰,因此委托类的功能越多越好

C、当发现某个子类并未带来该有的派生价值时,可以考虑使用移除子类(Remove Subclass)手法进行重构

D、将值域上移到父类(即字段上移 Pull Up Field)会有效减少子类的成员变量,只需要搬移值域,不需要搬移对该值域的操作方法

解释:

A:Extract Superclass(提炼超类)和Extract Interface(提炼接口)有很多的共通之处;Extract Superclass(提炼超类)提炼了classes中的重复代码;Extract Interface(提炼接口)只是提炼了classes中的接口,重复代码没有被消除,这个时候可以使用Extract Class(提炼类)的方法来将共同行为提炼出去,然后通过接口提供给其他客户使用。

B:没查到

D:我的理解操作方法也要搬移吧

2、题目2

牛客网公司真题_免费模拟题库_企业面试|笔试真题

有这样一个类:

class Eye
{
    public:
    void Look(void);
};

现在希望定义一个Head类,也想实现Look的功能,应该使用(B)方法,实现代码重用。

A、继承

B、组合

C、模板

D、过滤

解释:B Look是Eye本身所具有的功能,反过来Eye如果没有Look功能就不是一个完整的Eye。因此Look是Eye必不可少的一部分,就像车胎是汽车的一部分一样,代码复用最好的办法是用组合。

评论区有个解释比较好:

简单理解:Head has eyes,‘has a’ 关系是组合关系,而’is a‘是继承关系

3、题目3

每一种UML建模图都对应有各自不同的核心建模元素,其中顺序图(Sequence Diagram)的关键建模元素有哪些(BD )

A、控制流(Control Flow)

B、对象/角色(Object/Role)

C、状态(State)

D、消息(Message)

解释:这个题目就是涉及到一个知识点就是顺序图。

总结

未完待续…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值