软件工程与体系结构

软件工程与体系结构

设计模式

六大原则

原则解释
单一原则 (SRP)一个类只做一件事
开放-封闭原则(OCP)软件实体(类、模块、函数)可以拓展,但是不可修改
依赖倒转原则(DIP)A.高层模块不应该依赖底层,两个都应该依赖抽。B.抽象不应该依赖细节,细节依赖抽象
里氏代换原则(LSP)子类型必须能够替换掉它们的父类型
迪米特法则(LoD)如果两个类不必直接通信,那么这两个类不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可通过第三者发起这个调用
合成/聚合复用原则(CARP)尽量使用合成/聚合,尽量不要使用类继承

创建型模式

创建型模式有五种

  • 工厂模式
  • 抽象工厂模式
  • 单例模式
  • 构造者模式
  • 原型模式
单例模式

定义:保证一个类只有一个实例,并且提供一个全局访问点

场景:重量级的对象,不需要多个实例,如线程池,数据库连接池

image-20210627234927431
懒汉模式

定义:延迟加载,只有在真正使用的时候,才开始实例化

  • 线程安全问题
  • double check 加锁优化
  • 编译器(JIT),CPU有可能对指令进行重排序,导致使用到尚未初始化的实例,可以通过添加volatile关键字进行修饰

对于volatile修饰的字段,可以防止指令重排

饿汉模式

定义:类加载的初始化阶段就完成了实例的初始化。本质上就是借助于jvm类加载机制,保证实例的唯一性

类加载过程:

  • 加载二进制数据到内存中,生成对应的Class数据结构
  • 连接:a.验证,b.准备(给类的静态成员变量赋默认值),c.解析
  • 初始化:给类的静态变量赋初值

只有在真正使用对应的类时,才会触发初始化 如(当前类是启动类既main函数所在类,直接进行new操作,访问静态属性,访问静态方法,用反射访问类,初始化一个类的子类等)

工厂模式

定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。使一个类的实例化延迟到其子类

适用:当一个类不知道它所创建的对象的类的时候

作用:实现了创建者和调用者的分离

详细分类:

  • 简单工厂模式
    • 用来生产同一等级结构中的任意产品(对于增加新的产品,需要扩展已有代码)
  • 工厂方法模式
    • 用来生产同一等级结构中的固定产品(支持增加任意产品)
  • 抽象工厂模式
    • 围绕一个超级工厂创建其他工厂,该超级工厂又称为其他工厂的工厂

类图:

img

核心本质:

  • 实例化对象不适用new,用工厂方法代替
  • 将选择实现类,创建对象统一管理和控制。从而将调用者跟我们的实现类解耦
简单工厂模式

简称静态工厂模式

  • 不符合设计原则中的开闭原则,但是实际使用最多
  • 要增加一个新的产品,如果不修改代码,根本做不到
image-20210628135352619
工厂方法模式
  • 不修改已有类的前提下,通过增加新的工厂类实现扩展
image-20210628135159344

Car和CarFactory接口

image-20210628151807743

WuLing和WuLingFactory

image-20210628152003616

测试类

image-20210628152102478
抽象工厂模式

定义:抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类

适用场景:

  • 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
  • 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量的重复代码
  • 提供一个产品类的库,所有的产品以同样的接口出现,从而使得客户端不依赖于具体的实现

优点:

  • 具体产品在应用层的代码隔离,无需关心创建的细节
  • 将一个系列的产品统一到一起创建

缺点:

  • 规定了所有可能被创建的产品集合,产品簇中扩展新的产品困难;
  • 增加了系统的抽象性和理解难度
image-20210628152949141

类图:

image-20210628160338506

image-20210628163606479

结构型模式

结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者采用组合或聚合来组合对象。

由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。

结构型模式分为以下7种:

  • 代理模式
  • 适配器模式
  • 装饰者模式
  • 桥接模式
  • 外观模式
  • 组合模式
  • 享元模式
代理模式

定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

Java中的代理按照代理类生成时机不同又分为静态代理动态代理。静态代理代理类在编译期就生成,而动态代理代理类则是在Java运行时动态生成。动态代理又有JDK代理和CGLib代理两种。

分类:分为静态代理和动态代理

image-20210628164442210
静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
  • 客户:访问代理对象的人

优点

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
  • 公共业务就交给代理角色!实现了业务的分工
  • 公共业务发生扩展的时候,方便集中管理

缺点

  • ·一个真实角色就会产生一个代理角色;代码量会翻倍,开发效率会变低~

例子1:

代码步骤:

1、接口

//租房
public interface Rent {
    //出租房屋
    public void rent();
}

2、真实角色

//房东
public class Host implements Rent{

    @Override
    public void rent() {
        System.out.println("房东要出租房子");
    }
}

3、代理角色

//代理角色
public class Proxy implements Rent{
    private Host host;

    public Proxy(){

    }
    public Proxy(Host host){
        this.host = host;
    }

    //帮房东向别人租房子
    @Override
    public void rent() {
        seeHouse();
        host.rent(); //房东出租房子
        HeTong();
        fare();
    }

    //看房
    public void seeHouse(){
        System.out.println("中介代理带你去看房");
    }
    //签合同
    public void HeTong(){
        System.out.println("签合同");
    }
    //收中介费
    public void fare(){
        System.out.println("收中介费");
    }
}

4、客户端访问代理角色

public class Client {
    public static void main(String[] args) {
        //房东要出租房子
        Host host = new Host();
        //代理,中介帮房东租房子,代理角色一般会有一些附属操作
        Proxy proxy = new Proxy(host);

        //你不用找房东租房子,直接找中介租房即可
        proxy.rent();
    }
}

结果:

image-20210628170930940

例子2:火车站卖票

如果要买火车票的话,需要去火车站买票,坐车到火车站,排队等一系列的操作,显然比较麻烦。而火车站在多个地方都有代售点,我们去代售点买票就方便很多了。这个例子其实就是典型的代理模式,火车站是目标对象,代售点是代理对象。

类图:

image-20210629105931944
//卖票接口
public interface SellTickets {
    void sell();
}

//火车站  火车站具有卖票功能,所以需要实现SellTickets接口
public class TrainStation implements SellTickets {

    public void sell() {
        System.out.println("火车站卖票");
    }
}

//代售点
public class ProxyPoint implements SellTickets {

    private TrainStation station = new TrainStation();

    public void sell() {
        System.out.println("代理点收取一些服务费用");
        station.sell();
    }
}

//测试类
public class Client {
    public static void main(String[] args) {
        ProxyPoint pp = new ProxyPoint();
        pp.sell();
    }
}

从上面代码中可以看出测试类直接访问的是ProxyPoint类对象,也就是说ProxyPoint作为访问对象和目标对象的中介。同时也对sell方法进行了增强(代理点收取一些服务费用)。

c void sell() {
System.out.println(“代理点收取一些服务费用”);
station.sell();
}
}

//测试类
public class Client {
public static void main(String[] args) {
ProxyPoint pp = new ProxyPoint();
pp.sell();
}
}


从上面代码中可以看出测试类直接访问的是ProxyPoint类对象,也就是说ProxyPoint作为访问对象和目标对象的中介。同时也对sell方法进行了增强(代理点收取一些服务费用)。


> 注:此乃黄敢敢夜观各大网站视频所学即得笔记,如有雷同,请联系我进行删除!阿里嘎多


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值