设计模式(笔试+面试)

本文详细阐述了设计模式在软件开发中的重要性,重点关注系统复用、系统扩展以及各种设计模式如抽象工厂、模板方法、责任链、策略等的区别和应用场景。同时讨论了单例模式、工厂方法和代理模式的实现及其优缺点。

笔试

1、设计模式的两大主题是()

A、系统的维护与开发

B、对象组合与类的继承

C、系统架构与系统开发

D、系统复用与系统扩展

解释:设计模式是在软件开发中,针对在软件设计中反复出现的问题,所提出的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。设计模式的目的是提高代码的可重用性、使代码更容易被他人理解、保证代码可靠性,以及提高软件的开发效率和可维护性。

其中,系统复用(或代码复用)是指利用现有的、经过测试和验证的代码片段,而不是重新编写新的代码,从而提高开发效率和代码质量。系统扩展则是指在设计系统时,考虑到未来的变化和扩展性,使得系统能够容易地适应新的需求或变化,而不是每次有变化都需要进行大量的修改。

2、如果强调一系列相关产品的接口,以便联合使用它们的时候,应该选择何种设计模式:

A、模板方法模式

B、备忘录模式

C、抽象工厂模式

D、组合模式

解释:抽象工厂模式提供了一种方式,将一组具有共同主题的单个工厂方法封装起来,而不需要指定它们的具体类。客户端使用抽象工厂来创建一系列相关的对象,而不需要知道这些对象的具体类。这样,当系统需要新的产品族时,只需要添加新的具体工厂即可,而不需要修改现有的客户端代码。

抽象工厂模式的关键在于:

  • 它提供了一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类

  • 它使得客户端与具体产品的创建解耦,客户端只需要关心抽象工厂和抽象产品。

  • 当系统需要引入新产品族时,只需要增加新的具体工厂和具体产品,不需要修改客户端代码。

其他选项的解释:

A. 模板方法模式:定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。这与强调产品接口和联合使用不直接相关。

B. 备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。这通常用于实现撤销操作,与产品接口和联合使用关系不大。

D. 组合模式:允许你将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得客户端对单个对象和复合对象的使用具有一致性。虽然组合模式也涉及到对象的联合使用,但它更侧重于表示层次结构和一致性,而不是强调产品接口。

面试

学习资料:

行为型模式-策略模式和责任链模式对比_责任链模式和策略模式区别-CSDN博客

设计模式面试题(总结最全面的面试题!!!)-CSDN博客

创建型(5种):工厂方法模式,抽象工厂模式,单例模式,原型模式,建造者模式 ;

行为型(7种):适配器模式,代理模式,装饰器模式,外观模式,桥接模式,组合模式,享元模式 ;

构建型(11种):策略模式,责任链模式,模板方法模式,观察者模式,迭代子模式,命令模式,备忘录模式,状态模式,访问者模式,中介者模式,解释器模式 。

工厂模式

将对象的创建者和调用者分离

简单工厂:

一个工厂创建所有的产品,创建对象的类不需要知道对象的具体名称,而只需要知道创建对象的具体参数即可。其中工厂的职责过重(在核心工厂创建时体现),不利于维护和扩展。

Spring的IOC就使用了简单工厂模式:

  • 在实际的开发当中,传统的MVC三层架构需要控制层调用服务层,服务层调用dao层,dao层操作数据库,在对象调用过程中就需要手动的使用new关键字创建对象,此时类之间的依赖程度较高,耦合性就变高了。并且每次调用对象之前都需要手动创建,导致对象重复创建。

  • 当我们使用Spring的IOC来创建对象之后,IOC通过简单工厂模式来创建对象。但是使用工厂模式之后为什么就不会重复创建对象了呢?因为Spring还使用了单例模式,在Spring的IOC容器中有一个静态的Map集合来存储对象,保证每个对象只创建一次。

  • IOC创建对象的过程:

    • IOC通过XML资源文件获取到对象的具体属性(beanName);

    • 使用反射机制(优化if-else语句)获取到对象的类型;

    • 创建对象后放入静态Map容器中。

工厂接口:
public interface Car {
	public void run();
}
工厂创建产品1:
public class Bmw implements Car {
	public void run() {
		System.out.println("我是宝马汽车...");
	}
}
工厂创建产品2:
public class AoDi implements Car {
	public void run() {
		System.out.println("我是奥迪汽车..");
	}
}
核心工厂类(具体创建那种产品):
public class CarFactory {
	 public static Car createCar(String name) {
		if ("".equals(name)) {
             return null;
		}else if(name.equals("奥迪")){
			return new AoDi();
		}else if(name.equals("宝马")){
			return new Bmw();
		}
		return null;
	}
}
测试:
public class Client01 {
	public static void main(String[] args) {
		Car aodi  =CarFactory.createCar("奥迪");
		Car bmw  =CarFactory.createCar("宝马");
		aodi.run();
		bmw.run();
	}
}
工厂方法:

由于简单工厂模式中核心工厂负责创建所有对象,负担过重。工厂方法模式将创建对象的工作交给具体的子类,将核心工厂抽象化。

抽象工厂:

抽象工厂可以简单的理解为工厂的工厂,抽象工厂创建具体工厂,由具体工厂来创建产品

单例模式

实现一个类只有一个实例化对象(一个对象只被创建一次)

单例模式的应用:
  1. 网站的计数器,一般也是采用单例模式实现,否则难以实现同步

  2. 应用程序的日志应用,一般都是单例模式实现,只有一个实例去操作才好,否则内容不好追加显示。

  3. 多线程的线程池的设计一般也是采用单例模式,因为线程池要方便对池中的线程进行控制

  4. Windows的(任务管理器)就是很典型的单例模式,他不能打开俩个

  5. windows的(回收站)也是典型的单例应用。在整个系统运行过程中,回收站只维护一个实例。

优缺点:
优点
  1. 确保所有对象都访问同一个实例

  2. 单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。

  3. 提供了对唯一实例的受控访问

  4. 节约资源,提高性能

  5. 避免对共享资源的多重占用

缺点
  1. 扩展不便

  2. 违背了“单一职责原则”

  3. 不适用于变化的对象

具体实现(掌握前三种)
  1. 饿汉式:类初始化时,会立即加载该对象,线程天生安全,调用效率高。

  2. 懒汉式: 类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象,具备懒加载功能。

  3. 静态内部方式:结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全的。

  4. 枚举单例: 使用枚举实现单例模式 优点:实现简单、调用效率高,枚举本身就是单例,由jvm从根本上提供保障!避免通过反射和反序列化的漏洞, 缺点没有延迟加载。

  5. 双重检测锁方式 (因为JVM本质重排序的原因,可能会初始化多次,不推荐使用)

饿汉式:
//饿汉式
public class Demo1 {
    // 类初始化时,会立即加载该对象,线程安全,调用效率高
    private static Demo1 demo1 = new Demo1();
    private Demo1() {
        System.out.println("私有Demo1构造参数初始化");
    }
    public static Demo1 getInstance() {
        return demo1;
    }
    public static void main(String[] args) {
        Demo1 s1 = Demo1.getInstance();
        Demo1 s2 = Demo1.getInstance();
        System.out.println(s1 == s2);
    }
}
懒汉式:
//懒汉式
public class Demo2 {
    //类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象。
    private static Demo2 demo2;
    private Demo2() {
        System.out.println("私有Demo2构造参数初始化");
    }
    public synchronized static Demo2 getInstance() {
        if (demo2 == null) {
            demo2 = new Demo2();
        }
        return demo2;
    }
    public static void main(String[] args) {
        Demo2 s1 = Demo2.getInstance();
        Demo2 s2 = Demo2.getInstance();
        System.out.println(s1 == s2);
    }
}

静态内部类:
// 静态内部类方式
public class Demo3 {
    private Demo3() {
        System.out.println("私有Demo3构造参数初始化");
    }
    public static class SingletonClassInstance {
        private static final Demo3 DEMO_3 = new Demo3();
    }
    // 方法没有同步
    public static Demo3 getInstance() {
        return SingletonClassInstance.DEMO_3;
    }
    public static void main(String[] args) {
        Demo3 s1 = Demo3.getInstance();
        Demo3 s2 = Demo3.getInstance();
        System.out.println(s1 == s2);
    }
}

代理模式

  • 通过代理对象控制主体对象的访问时机,从而在主体方法调用之前,调用之后增加一些与业务无关的功能,使得额外添加的功能和主要业务分离。

  • 与Spring的AOP(面向切面编程)相似,在不改变原有代码的基础上横切加入新的功能;

静态代理:简单代理,在程序运行之前就已经存在的代理类,无需动态的创建。

动态代理:使用反射机制完成代理

哪些地方应用到了代理模式
  • AOP

  • 事务处理

  • 日志打印

  • 异常处理

  • 权限控制

策略模式

  • 定义了一系列的算法或者逻辑或者相同意义的操作,并且将每一个算法、逻辑、封装起来,而且使他们还可以相互替换。

  • 可以很好的简化if-else所带来的复杂判断,使得代码更加容易维护。

责任链模式

  • 责任链模式用于将请求传递给一系列处理器,直到找到一个合适的处理者

  • 可以很好的简化if-else所带来的复杂判断,使得代码更加容易维护。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值