day25_软件设计模式

2023-12-14 09:40:32

设计原则

1)创建软件应用程序是为了满足不断变化和发展的需求。一个成功的应用程序还应该提供一种简单的方法来扩展它以满足不断变化的期望。如果在设计和开发软件时应用一组面向对象的设计原则和模式,则可以避免或解决这些常见问题。

2)面向对象的设计原则也被称为 SOLID 。在设计和开发软件时可以应用这些原则,以便创建易于维护和开发的程序。

SOLID 原则包括,单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。

1、单一职责原则:每个类只负责做一件事

专业的人做专业的事。每个类只负责做一件事

单一职责原则,其它就是“高内聚”的体现。

每个类只负责做一件事, 对外只提供一个功能,而引起类的变化 的原因应该只有一个。

2、开闭原则 : 对扩展开放,对修改关闭

核心思想:一个对象 对扩展开放,对修改关闭

对类的改动是通过增加代码进行,而不是修改代码

如何实现?这就需要借助于抽象 和多态。即把可能变化 的内容抽象 出来.

因为抽象的部分是相对稳定

3、里氏替换原则

子类可以扩展父类的功能,但不能改变父类原有的功能

子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。

4、接口隔离原则

别人不需要的东西不要强加给人家。

接口隔离原则是为了约束接口,降低类对接口的依赖。

接口隔离原则是为了约束接口,降低类对接口的依赖。
接口隔离原则的优点:

  1. 灵活性,可维护性增强
  2. 高内聚,低耦合
  3. 减少代码冗余(减少了方法的实现)
  4. 体现对象层次

5、依赖倒置原则

依赖于抽象,而不是依赖于具体,依赖注入模式

依赖倒置原则(Dependency Inversion Principle,DIP)是面向对象设计中的一个原则,它是SOLID原则中的一部分。依赖倒置原则的核心思想是:

高层模块不应该依赖于低层模块,二者都应该依赖于抽象; 抽象不应该依赖于具体细节,而具体细节应该依赖于抽象。

(依赖于抽象)

简而言之,依赖倒置原则要求我们通过抽象来解耦高层模块和低层模块之间的依赖关系,从而使系统更加灵活、可扩展和易于维护。

核心思路: 要依赖于抽象 ,不要依赖于具体

为了实现这一原则 ,在编程时针对抽象类或者接口编程,而不是具体要求实现

设计模式

设计模式是一套反复被使用,经过验证的,代码的总结 ;

设计模式不是具体的方法,而一种思想.

学习设计模式就是要建立面向对象的思想,尽可能的面向接口编程,低耦合,高内聚,使程序实现复用

设计模式的几个要素

  1. 名字——必须有一个简单,有意义的名称
  2. 问题——描述在何使用
  3. 解决方案——如何去解决问题
  4. 效果——模式优点缺点

设计模式分类:

创建型模式 对象的创建

结构型模式 对象的组成(结构)

行为型模式 对象的行为

创建型模式: 简单工厂模式, 工厂模式,单例模式等。。。

**结构型模式:**外观模式,适配器模式,装饰模式 。。。

**行为型模式:**模板方法模式,观察者模式,状态模式。。。

常见设计模式

1、简单工厂模式

又称为静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例

优点:客户端不需要负责创建对象,明确了各位类的职责

缺点:静态工厂负责创建对象,如果有新的对象增加,或者创建方式不同,需要不断的修改工厂类,不利于后期维护

public class AnimalFoctory {
    private AnimalFoctory(){

    }
    public static Animal createAnimal(String type){
        if("dog".equals(type)){
            return new Dog();
        }else if("cat".equals(type)){
            return new Cat();
        }else{
            return null;
        }
    }
    public static Dog createDog(){
        return  new Dog();
    }
    public static Cat createCat(){
        return  new Cat();
    }
}
// 如果我先再想要添加一个pig的构建,需要修改AnimalFactory类的代码,不利于后期维护
2、工厂模式

工厂模式: 抽象工厂类负责定义创建对象的接口,具体对象的创建由继承抽象工厂的具体类实现

优点:客户端不需要负责创建对象,明确了各位类的职责 ; 如果 新的对象增加,不修改已有的代码,增加了维护性和扩展性

缺点:需要额外编写代码,增加了工作量

// 创建一个抽象工程接口
interface Factory {
    public abstract Animal createAnimal();
}
// 创建Animal基类
abstract class Animal {
    public abstract void eat();
}
// 创建Cat类继承自Animal类
class Cat extends Animal {
    public void eat(){
        System.out.println("猫吃老鼠");
    }
}

// 创建一个专门用来创建cat对象的工厂类的具体实现
class CatFoctory implements Factory{
    @Override
    public Animal createAnimal() {
        return new Cat();
    }
}
// 调用工厂类创建cat对象
public class Demo{
    public static void main(String[] args){
        Animal cat = new CatFactory().createAnimal();
        cat.eat(); // 打印——"猫吃老鼠"
    }
}

//如果我想 扩展创建Dog类对象的方法,那么不需要修改已有的代码,而是再创建一个Factory接口的实现类,去实现创建Dog的方法(类似于模板)
3、单例模式

单例模式: 确保一个类在内存中只有一个实例,此实例必须自动创建,并且对外提供获取实例的方法

要求:

  1. 某个类只能有一个实例;
  2. 必须自行创建这个实例;
  3. 必须自行向整个系统提供这个实例。

在这里插入图片描述

优缺点:
  1. 优点:
    • 节约系统资源
    • 提供了对唯一实例的受控访问
  2. 缺点:
    • 在一定程度上,违背了“单一职责原则”
①(饿汉式): 类加载的就创建对象
public class Singleton {
    // 为了让静态方法可以访问此对象,所以把它变成静态的
    // 为了让外界不能直接访问,加private
    private static Singleton s = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return s;
    }
}
②(懒汉式):用的时候,才去创建
public class Singleton2 {
    private static Singleton2 s = null;
    private Singleton2(){}
    public static Singleton2 getInstance(){
        if(Objects.nonNull(s)){
            s = new Singleton2();
        }
        return s;
    }
}
面试题:单例模式的思想是什么?回答上述代码体现。
  • 在开发中用:饿汉式

    Runtime类:java官方都用的饿汉式编程我们跟着用就是了

    public class Runtime {
        private static Runtime currentRuntime = new Runtime();
        public static Runtime getRuntime() {
            return currentRuntime;
        }
        private Runtime() {}
     }
    
  • 面试的时候回答:懒汉式(可能会出现问题的)

    1. 懒加载(延迟加载)
    2. 线程安全问题:解决方法:加同步锁锁
public class Singleton2 {
    private static Singleton2 s = null;
    private Singleton2(){}
        // 给获取方法加同步锁
    public static Singleton2 getInstance(){
        if(Objects.nonNull(s)){
            s = new Singleton2();
        }
        return s;
    }
}

4、模版设计模式

需求: 计算出一段代码的运行时间

思路:在这段代码的前面加上获取当前时间的方法记录当前的时间毫秒数
    在这段代码结束之后再记录结束是的时间毫秒数
    将两个毫秒数相减,就可以得到代码执行的时间了。
    
问题:
    1、我们并不知道这段代码到底是什么???
    	那么该怎么设计呢???
    	解决方案:使用模板模式,创建一个抽象的模板类
    
abstract class TimeUtils{
    // 获取执行时间毫秒数的方法
    public long getRunTimes(){
        long start = System.currentTimeMillis();
        code();
        long end = System.currentTimeMillis();
        return end - start;
    }
    // 需要实现我设计的模板的方法,就是把需要计算运行时间的代码给实现
    public abstract void code();
}

// 使用这个模板的类
class MyClazz extends TimeUtils{
    @Override
    public void code() {
        // 需要计算打印0-9999用的时间的毫秒数
        for (int i = 0; i < 10000; i++) {
            System.out.println(i);
        }
    }
}

// 测试
public class Demo {
    public static void main(String[] args) {
        TimeUtils timeUtils = new MyClazz();
        System.out.println(timeUtils.getRunTimes()+"毫秒");
    }
}

优点: 满足用户需求,灵活多变

缺点:如果算法需要改变,需要修改抽象类

装饰设计模式(扩展对象)

优点:

可以提供比继承更灵活的扩展对象的功能

缺点:可以任意组合

已经学过的装饰:就是把一个对象通过另一个对象包装一下

Scanner scanner = new Scanner(System.in);

文章来源:https://blog.csdn.net/qq_64646478/article/details/134986850
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。