(计算机基础 核心知识)设计模式
1.简述单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
何时使用:当您想控制实例数目,节省系统资源的时候。
如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
关键代码:构造函数是私有的。
在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
懒汉式,第一次调用才初始化,避免内存浪费。
public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
饿汉式,类加载时就初始化。
2.简述观察者模式
观察者模式表示的是一种对象与对象之间具有依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
如何解决:使用面向对象技术,可以将这种依赖关系弱化。
关键代码:在抽象类里有一个 ArrayList 存放观察者们。
应用实例: 1、拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。 2、西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个乌龟就是观察者,他观察菩萨洒水这个动作。
优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
缺点: 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
使用场景:
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
3.简述适配器模式
适配器模式将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作。
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。
意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
主要解决:主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。
何时使用: 1、系统需要使用现有的类,而此类的接口不符合系统的需要。 2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。 3、通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)
如何解决:继承或依赖(推荐)。
关键代码:适配器继承或依赖已有的对象,实现想要的目标接口。
优点: 可以让任何两个没有关联的类一起运行。 2、提高了类的复用。 3、增加了类的透明度。 4、灵活性好。
缺点: 过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。 2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
使用场景:有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。
注意事项:适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。
4.简述简单工厂模式
简单工厂模式指由一个工厂对象来创建实例,适用于工厂类负责创建对象较少的情况。例子:Spring 中的 BeanFactory 使用简单工厂模式,产生 Bean 对象。
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
5.简述工厂模式
工厂方法模式指定义一个创建对象的接口,让接口的实现类决定创建哪种对象,让类的实例化推迟到子类中进行。例子:Spring 的 FactoryBean 接口的 getObject 方法也是工厂方法。
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
主要解决:主要解决接口选择的问题。
何时使用:我们明确地计划不同条件下创建不同实例时。
如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。
构建宠物的工厂
// 号称什么宠物都有 public interface AnimalFactory { // 可以获取任何的宠物 Animal createAnimal(); }
当然了,主流的宠物得进货一些先放在店里充充门面,一些特殊的宠物就告诉顾客要时间进货~
- 所以,我们就有了构建猫和狗的工厂(继承着所有宠物的工厂)
猫工厂:
// 继承着宠物工厂 public class CatFactory implements AnimalFactory { @Override // 创建猫 public Animal createAnimal() { return new Cat(); } }
狗工厂也是一样的:
// 继承着宠物工厂 public class DogFactory implements AnimalFactory { // 创建狗 @Override public Animal createAnimal() { return new Dog(); } }
嗯,还有我们的实体类:猫、狗、动物(多态:猫和狗都是动物,可以直接用动物来表示了)
动物实体类:
public abstract class Animal { // 所有的动物都会吃东西 public abstract void eat(); }
猫实体类:
public class Cat extends Animal { // 猫喜欢吃鱼 @Override public void eat() { System.out.println("猫吃鱼"); } }
狗实体类:
public class Dog extends Animal { // 狗喜欢吃肉 @Override public void eat() { System.out.println("狗吃肉"); } }
那么现在Java3y想要一只狗,跟了宠物店老板说,宠物店老板就去找狗回来了:
// 去找狗工厂拿一只狗过来 AnimalFactory f = new DogFactory(); // 店主就拿到了一只狗给Java3y Animal a = f.createAnimal(); a.eat(); System.out.println("关注公众号:Java3y");
那么现在Java3y想要一只猫,跟了宠物店老板说,宠物店老板就去找猫回来了:
// 去找猫工厂拿一只猫过来 AnimalFactory ff = new CatFactory(); // 店主就拿到了一只猫给Java3y Animal aa = ff.createAnimal(); aa.eat(); System.out.println("关注公众号:Java3y");
如果这个时候Java3y说想要一只蜥蜴怎么办啊?没问题啊,店主搞个蜥蜴工厂就好了~~
// 要买蜥蜴.. AnimalFactory fff = new LizardFactory(); Animal aaa = ff.createAnimal(); aaa.eat();
优点:
- 1:客户端不需要在负责对象的创建,明确了各个类的职责
- 2:如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可
- 3:不会影响已有的代码,后期维护容易,增强系统的扩展性
缺点:
- 1:需要额外的编写代码,增加了工作量
简单/静态工厂模式
现在宠物店生意不好做啊,号称“什么宠物都有",这吹过头了~~于是店主只卖两种常见的宠物了。
- 既然就只有两种宠物的话,那就没必要有”猫厂“、”狗厂“了,一个猫狗厂就行了!
所以我们的工厂是这样子的:
public class AnimalFactory { public static Dog createDog() { return new Dog(); } public static Cat createCat() { return new Cat(); } // 外界想要猫要狗,这里创建就好了
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
曾获多国内大厂的 ssp 秋招 offer,且是Java5年的沉淀老兵(不是)。专注后端高频面试与八股知识点,内容系统详实,覆盖约 30 万字面试真题解析、近 400 个热点问题(包含大量场景题),60 万字后端核心知识(含计网、操作系统、数据库、性能调优等)。同时提供简历优化、HR 问题应对、自我介绍等通用能力。考虑到历史格式混乱、质量较低、也在本地积累了大量资料,故准备从头重构专栏全部内容