设计模式面试突击
作者:互联网
Java面试中设计模式的常见面试题总结。
文章目录
一、设计模式
1.1 什么是设计模式?
设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性
。
1.2 设计模式分类
设计模式总共有 23 种,总体来说可以分为三大类:创建型模式( Creational Patterns )
、结构型模式( Structural Patterns )
和行为型模式( Behavioral Patterns )
创建型模式
,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式
,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式
,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
1.3 设计模式的六大原则
开放封闭原则(Open Close Principle)
原则思想
:尽量通过扩展软件实体来解决需求变化,而不是通过修改已有的代码来完成变化描述
:一个软件产品在生命周期内,都会发生变化,既然变化是一个既定的事实,我们就应该在设计的时候尽量适应这些变化,以提高项目的稳定性和灵活性。优点
:单一原则告诉我们,每个类都有自己负责的职责,里氏替换原则不能破坏继承关系的体系。
里氏代换原则(Liskov Substitution Principle)
原则思想
:使用的基类可以在任何地方使用继承的子类,完美的替换基类。描述
:子类可以扩展父类的功能,但不能改变父类原有的功能。子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法,子类中可以增加自己特有的方法。优点
:增加程序的健壮性,即使增加了子类,原有的子类还可以继续运行,互不影响。
依赖倒转原则(Dependence Inversion Principle)
- 依赖倒置原则的核心思想是面向接口编程.
- 依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,
- 这个是开放封闭原则的基础,具体内容是:对接口编程,依赖于抽象而不依赖于具体。
接口隔离原则(Interface Segregation Principle)
- 描述:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
- 例如:支付类的接口和订单类的接口,需要把这俩个类别的接口变成俩个隔离的接口
迪米特法则(最少知道原则)(Demeter Principle)
- 原则思想:一个对象应当对其他对象有尽可能少地了解,简称类间解耦
- 大概意思就是一个类尽量减少自己对其他对象的依赖,原则是低耦合,高内聚,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率。
- 优点:低耦合,高内聚。
单一职责原则(Principle of single responsibility)
- 原则思想:一个方法只负责一件事情。
- 描述:单一职责原则很简单,一个方法 一个类只负责一个职责,各个职责的程序改动,不影响其它程序。 这是常识,几乎所有程序员都会遵循这个原则。
- 优点:降低类和类的耦合,提高可读性,增加可维护性和可拓展性,降低可变性的风险。
1.4 设计模式的优点
- 设计模式可在多个项目中重用。
- 设计模式提供了一个帮助定义系统架构的解决方案。
- 设计模式吸收了软件工程的经验。
- 设计模式为应用程序的设计提供了透明性。
- 设计模式是被实践证明切实有效的,由于它们是建立在专家软件开发人员的知识和经验之上的。
二、单例模式
2.1 什么是单例模式?
单例模式是一种常用的软件设计模式,在应用这个模式时,单例对象的类必须保证只有一个实例存在,整个系统只能使用一个对象实例。
2.2 单例模式优缺点及使用场景
优点
:不会频繁地创建和销毁对象,浪费系统资源。
缺点
:单例类的扩展困难,不适用于变化的对象
使用场景
:IO 、数据库连接、Redis 连接、网站的计数器、Windows的(任务管理器)、windows的(回收站)、多线程的线程池的设计等。
2.3 如何创建单例模式
- 如果
不需要延迟加载单例
,可以使用枚举或者饿汉式
,相对来说枚举性好于饿汉式。 - 如果
需要延迟加载
,可以使用静态内部类或者懒汉式
,相对来说静态内部类好于懒韩式。 最好使用饿汉式
创建方式:(主要使用懒汉和懒汉式)
饿汉式
:类初始化时,会立即加载该对象,线程天生安全,调用效率高。懒汉式
: 类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象,具备懒加载功能。静态内部方式
:结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全的。枚举单例
: 使用枚举实现单例模式 优点:实现简单、调用效率高,枚举本身就是单例,由jvm从根本上提供保障!避免通过反射和反序列化的漏洞,缺点没有延迟加载。双重检测锁方式
(因为JVM本质重排序的原因,可能会初始化多次,不推荐使用)
饿汉式:类初始化时,会立即加载该对象,线程天生安全,调用效率高。
单例模式代码实现:
class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
单例模式调用代码:
public class Lesson {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1 == singleton2);
}
}
程序的输出结果:true
可以看出以上单例模式是在类加载的时候就创建了,这样会影响程序的启动速度,那如何实现单例模式的延迟加载?在使用时再创建?
单例延迟加载代码:
// 单例模式-延迟加载版
class SingletonLazy {
private static SingletonLazy instance;
public static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
以上为非线程安全的,单例模式如何支持多线程?
使用 synchronized
来保证,单例模式的线程安全代码:
class SingletonLazy {
private static SingletonLazy instance;
public static synchronized SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
三、简单工厂模式
3.1 什么是简单工厂模式?
简单工厂模式又叫静态工厂方法模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。比如,一台咖啡机就可以理解为一个工厂模式,你只需要按下想喝的咖啡品类的按钮(摩卡或拿铁),它就会给你生产一杯相应的咖啡,你不需要管它内部的具体实现,只要告诉它你的需求即可。
3.2 简单工厂模式优缺点及使用场景
优点:
- 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象;
- 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量;
- 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点:
- 不易拓展,一旦添加新的产品类型,就不得不修改工厂的创建逻辑;
- 产品类型较多时,工厂的创建逻辑可能过于复杂,一旦出错可能造成所有产品的创建失败,不利于系统的维护。
3.3 如何创建简单工厂模式
简单工厂代码实现:
class Factory {
public static String createProduct(String product) {
String result = null;
switch (product) {
case "Mocca":
result = "摩卡";
break;
case "Latte":
result = "拿铁";
break;
default:
result = "其他";
break;
}
return result;
}
}
四、抽象工厂模式
4.1 什么是抽象工厂模式?
抽象工厂模式是在简单工厂的基础上将未来可能需要修改的代码抽象出来,通过继承的方式让子类去做决定。
比如,以上面的咖啡工厂为例,某天我的口味突然变了,不想喝咖啡了想喝啤酒,这个时候如果直接修改简单工厂里面的代码,这种做法不但不够优雅,也不符合软件设计的“开闭原则”,因为每次新增品类都要修改原来的代码。这个时候就可以使用抽象工厂类了,抽象工厂里只声明方法,具体的实现交给子类(子工厂)去实现,这个时候再有新增品类的需求,只需要新创建代码即可。
4.2 抽象工厂模式优缺点及使用场景
4.3 如何创建抽象工厂模式
抽象工厂实现代码如下:
public class AbstractFactoryTest {
public static void main(String[] args) {
// 抽象工厂
String result = (new CoffeeFactory()).createProduct("Latte");
System.out.println(result); // output:拿铁
}
}
// 抽象工厂
abstract class AbstractFactory{
public abstract String createProduct(String product);
}
// 啤酒工厂
class BeerFactory extends AbstractFactory{
@Override
public String createProduct(String product) {
String result = null;
switch (product) {
case "Hans":
result = "汉斯";
break;
case "Yanjing":
result = "燕京";
break;
default:
result = "其他啤酒";
break;
}
return result;
}
}
// 咖啡工厂
class CoffeeFactory extends AbstractFactory{
@Override
public String createProduct(String product) {
String result = null;
switch (product) {
case "Mocca":
result = "摩卡";
break;
case "Latte":
result = "拿铁";
break;
default:
result = "其他咖啡";
break;
}
return result;
}
}
五、观察者模式
5.1 什么是观察者模式?
观察者模式是定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
5.2 观察者模式优缺点及使用场景
优点:
- 观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色;
- 观察者模式在观察目标和观察者之间建立一个抽象的耦合;
- 观察者模式支持广播通信;
- 观察者模式符合开闭原则(对拓展开放,对修改关闭)的要求。
缺点:
- 如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间;
- 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃;
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
5.3 如何创建观察者模式
在观察者模式中有如下角色:
Subject
:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象;ConcreteSubject
:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知;Observer
:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己;ConcrereObserver
:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
观察者模式实现代码如下。
1)定义观察者(消息接收方)
// 观察者(消息接收方)
interface Observer {
public void update(String message);
}
// 具体的观察者(消息接收方)
class ConcrereObserver implements Observer {
private String name;
public ConcrereObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + ":" + message);
}
}
2)定义被观察者(消息发送方)
// 被观察者(消息发布方)
interface Subject {
// 增加订阅者
public void attach(Observer observer);
// 删除订阅者
public void detach(Observer observer);
// 通知订阅者更新消息
public void notify(String message);
}
// 具体被观察者(消息发布方)
class ConcreteSubject implements Subject {
// 订阅者列表(存储信息)
private List<Observer> list = new ArrayList<Observer>();
@Override
public void attach(Observer observer) {
list.add(observer);
}
@Override
public void detach(Observer observer) {
list.remove(observer);
}
@Override
public void notify(String message) {
for (Observer observer : list) {
observer.update(message);
}
}
}
3)代码调用
public class ObserverTest {
public static void main(String[] args) {
// 定义发布者
ConcreteSubject concreteSubject = new ConcreteSubject();
// 定义订阅者
ConcrereObserver concrereObserver = new ConcrereObserver("老王");
ConcrereObserver concrereObserver2 = new ConcrereObserver("Java");
// 添加订阅
concreteSubject.attach(concrereObserver);
concreteSubject.attach(concrereObserver2);
// 发布信息
concreteSubject.notify("更新了");
}
}
程序执行结果如下:
老王:更新了
Java:更新了
六、装饰器模式
6.1 什么是装饰器模式?
装饰器模式是指动态地给一个对象增加一些额外的功能,同时又不改变其结构。
6.2 装饰器模式优缺点及使用场景
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
装饰器模式的关键:装饰器中使用了被装饰的对象。
比如,创建一个对象“laowang”,给对象添加不同的装饰,穿上夹克、戴上帽子…,这个执行过程就是装饰者模式,
6.3 如何创建装饰器模式
实现代码如下。
1)定义顶层对象,定义行为
interface IPerson {
void show();
}
2)定义装饰器超类
class DecoratorBase implements IPerson{
IPerson iPerson;
public DecoratorBase(IPerson iPerson){
this.iPerson = iPerson;
}
@Override
public void show() {
iPerson.show();
}
}
3)定义具体装饰器
class Jacket extends DecoratorBase {
public Jacket(IPerson iPerson) {
super(iPerson);
}
@Override
public void show() {
// 执行已有功能
iPerson.show();
// 定义新行为
System.out.println("穿上夹克");
}
}
class Hat extends DecoratorBase {
public Hat(IPerson iPerson) {
super(iPerson);
}
@Override
public void show() {
// 执行已有功能
iPerson.show();
// 定义新行为
System.out.println("戴上帽子");
}
}
4)定义具体对象
class LaoWang implements IPerson{
@Override
public void show() {
System.out.println("什么都没穿");
}
}
5)装饰器模式调用
public class DecoratorTest {
public static void main(String[] args) {
LaoWang laoWang = new LaoWang();
Jacket jacket = new Jacket(laoWang);
Hat hat = new Hat(jacket);
hat.show();
}
}
七、模板方法模式
7.1 什么是模板方法模式?
模板方法模式是指定义一个模板结构,将具体内容延迟到子类去实现。
7.2 模板方法模式优缺点及使用场景
优点:
- 提高代码复用性:将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中;
- 实现了反向控制:通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制并且符合开闭原则。
以给冰箱中放水果为例,比如,我要放一个香蕉:开冰箱门 → 放香蕉 → 关冰箱门;如果我再要放一个苹果:开冰箱门 → 放苹果 → 关冰箱门。可以看出它们之间的行为模式都是一样的,只是存放的水果品类不同而已,这个时候就非常适用模板方法模式来解决这个问题
7.3 如何创建模板方法模式
实现代码如下:
// 添加模板方法
abstract class Refrigerator {
public void open() {
System.out.println("开冰箱门");
}
public abstract void put();
public void close() {
System.out.println("关冰箱门");
}
}
class Banana extends Refrigerator {
@Override
public void put() {
System.out.println("放香蕉");
}
}
class Apple extends Refrigerator {
@Override
public void put() {
System.out.println("放苹果");
}
}
// 调用模板方法
public class TemplateTest {
public static void main(String[] args) {
Refrigerator refrigerator = new Banana();
refrigerator.open();
refrigerator.put();
refrigerator.close();
}
}
程序执行结果:
开冰箱门
放香蕉
关冰箱门
八、代理模式
8.1 什么是代理模式?
代理模式是给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
8.2 代理模式优缺点及使用场景
优点:
- 代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度;
- 可以灵活地隐藏被代理对象的部分功能和服务,也增加额外的功能和服务。
缺点:
- 由于使用了代理模式,因此程序的性能没有直接调用性能高;
- 使用代理模式提高了代码的复杂度。
举一个生活中的例子:比如买飞机票,由于离飞机场太远,直接去飞机场买票不太现实,这个时候我们就可以上携程 App 上购买飞机票,这个时候携程 App 就相当于是飞机票的代理商。
8.3 如何创建代理模式
代理模式实现代码如下:
// 定义售票接口
interface IAirTicket {
void buy();
}
// 定义飞机场售票
class AirTicket implements IAirTicket {
@Override
public void buy() {
System.out.println("买票");
}
}
// 代理售票平台
class ProxyAirTicket implements IAirTicket {
private AirTicket airTicket;
public ProxyAirTicket() {
airTicket = new AirTicket();
}
@Override
public void buy() {
airTicket.buy();
}
}
// 代理模式调用
public class ProxyTest {
public static void main(String[] args) {
IAirTicket airTicket = new ProxyAirTicket();
airTicket.buy();
}
}
九、策略模式
9.1 什么是策略模式?
策略模式是指定义一系列算法,将每个算法都封装起来,并且使他们之间可以相互替换。
9.2 策略模式优缺点及使用场景
优点:遵循了开闭原则,扩展性良好。
缺点:随着策略的增加,对外暴露越来越多。
以生活中的例子来说,比如我们要出去旅游,选择性很多,可以选择骑车、开车、坐飞机、坐火车等,就可以使用策略模式,把每种出行作为一种策略封装起来,后面增加了新的交通方式了,如超级高铁、火箭等,就可以不需要改动原有的类,新增交通方式即可,这样也符合软件开发的开闭原则。
9.3 如何创建策略模式
策略模式实现代码如下:
// 声明旅行
interface ITrip {
void going();
}
class Bike implements ITrip {
@Override
public void going() {
System.out.println("骑自行车");
}
}
class Drive implements ITrip {
@Override
public void going() {
System.out.println("开车");
}
}
// 定义出行类
class Trip {
private ITrip trip;
public Trip(ITrip trip) {
this.trip = trip;
}
public void doTrip() {
this.trip.going();
}
}
// 执行方法
public class StrategyTest {
public static void main(String[] args) {
Trip trip = new Trip(new Bike());
trip.doTrip();
}
}
程序执行的结果:
骑自行车
十、适配器模式
10.1 什么是适配器模式?
适配器模式是将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够在一起工作。
10.2 适配器模式优缺点及使用场景
优点:
- 可以让两个没有关联的类一起运行,起着中间转换的作用;
- 灵活性好,不会破坏原有的系统。
**缺点:**过多地使用适配器,容易使代码结构混乱,如明明看到调用的是 A 接口,内部调用的却是 B 接口的实现。
以生活中的例子来说,比如有一个充电器是 MicroUSB 接口,而手机充电口却是 TypeC 的,这个时候就需要一个把 MicroUSB 转换成 TypeC 的适配器
10.3 如何创建适配器模式
适配器实现代码如下:
// 传统的充电线 MicroUSB
interface MicroUSB {
void charger();
}
// TypeC 充电口
interface ITypeC {
void charger();
}
class TypeC implements ITypeC {
@Override
public void charger() {
System.out.println("TypeC 充电");
}
}
// 适配器
class AdapterMicroUSB implements MicroUSB {
private TypeC typeC;
public AdapterMicroUSB(TypeC typeC) {
this.typeC = typeC;
}
@Override
public void charger() {
typeC.charger();
}
}
// 测试调用
public class AdapterTest {
public static void main(String[] args) {
TypeC typeC = new TypeC();
MicroUSB microUSB = new AdapterMicroUSB(typeC);
microUSB.charger();
}
}
程序执行结果:
TypeC 充电
十一、常见设计模式面试问题
11.1 JDK 类库常用的设计模式有哪些?
1)工厂模式
java.text.DateFormat
工具类,它用于格式化一个本地日期或者时间。
public final static DateFormat getDateInstance();
public final static DateFormat getDateInstance(int style);
public final static DateFormat getDateInstance(int style,Locale locale);
加密类
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
Cipher cipher = Cipher.getInstance("DESede");
2)适配器模式
把其他类适配为集合类
List<Integer> arrayList = java.util.Arrays.asList(new Integer[]{1,2,3});
List<Integer> arrayList = java.util.Arrays.asList(1,2,3);
3)代理模式
如 JDK 本身的动态代理。
interface Animal {
void eat();
}
class Dog implements Animal {
@Override
public void eat() {
System.out.println("The dog is eating");
}
}
class Cat implements Animal {
@Override
public void eat() {
System.out.println("The cat is eating");
}
}
// JDK 代理类
class AnimalProxy implements InvocationHandler {
private Object target; // 代理对象
public Object getInstance(Object target) {
this.target = target;
// 取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用前");
Object result = method.invoke(target, args); // 方法调用
System.out.println("调用后");
return result;
}
}
public static void main(String[] args) {
// JDK 动态代理调用
AnimalProxy proxy = new AnimalProxy();
Animal dogProxy = (Animal) proxy.getInstance(new Dog());
dogProxy.eat();
}
4)单例模式
全局只允许有一个实例,比如:
Runtime.getRuntime();
5)装饰器
为一个对象动态的加上一系列的动作,而不需要因为这些动作的不同而产生大量的继承类。
java.io.BufferedInputStream(InputStream);
java.io.DataInputStream(InputStream);
java.io.BufferedOutputStream(OutputStream);
java.util.zip.ZipOutputStream(OutputStream);
java.util.Collections.checkedList(List list, Class type) ;
6)模板方法模式
定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中。
比如,Arrays.sort() 方法,它要求对象实现 Comparable 接口。
class Person implements Comparable{
private Integer age;
public Person(Integer age){
this.age = age;
}
@Override
public int compareTo(Object o) {
Person person = (Person)o;
return this.age.compareTo(person.age);
}
}
public class SortTest(){
public static void main(String[] args){
Person p1 = new Person(10);
Person p2 = new Person(5);
Person p3 = new Person(15);
Person[] persons = {p1,p2,p3};
//排序
Arrays.sort(persons);
}
}
11.2 IO 使用了什么设计模式?
IO 使用了适配器模式和装饰器模式。
适配器模式
:由于 InputStream 是字节流不能享受到字符流读取字符那么便捷的功能,借助 InputStreamReader将其转为 Reader 子类,因而可以拥有便捷操作文本文件方法;装饰器模式
:将 InputStream 字节流包装为其他流的过程就是装饰器模式,比如,包装为 FileInputStream、ByteArrayInputStream、PipedInputStream 等。
11.3 Spring 中都使用了哪些设计模式?
Spring 框架使用的设计模式如下。
代理模式
:在 AOP 中有使用单例模式
:bean 默认是单例模式模板方法模式
:jdbcTemplate工厂模式
:BeanFactory观察者模式
:Spring 事件驱动模型就是观察者模式很经典的一个应用,比如,ContextStartedEvent 就是ApplicationContext 启动后触发的事件适配器模式
:Spring MVC 中也是用到了适配器模式适配 Controller
11.4 代理模式有哪些类型?
保护代理
:它根据某些条件控制对真实主题的访问。虚拟代理
:虚拟代理用于实例化昂贵的对象。代理管理实现中真实主体的生命周期。它决定创建实例的需要以及何时重用实例。虚拟代理优化性能。缓存代理
:缓存代理用于缓存对真实主题的昂贵调用。代理可以使用许多缓存策略。其中一些是通读、写、缓存和基于时间的。缓存代理用于提高性能。远程代理
:远程代理用于分布式对象通信。远程代理通过调用本地对象方法在远程对象上执行。智能代理
:智能代理用于实现对对象的日志调用和引用计数。
11.5 mvc模式
MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。
Model(模型)
- 模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。View(视图)
- 视图代表模型包含的数据的可视化。Controller(控制器)
- 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。
参考:
标签:void,观察者,模式,class,面试,突击,设计模式,public 来源: https://blog.csdn.net/weixin_44052055/article/details/123029689