设计原则

类型
设计模式的类型总共分为:3大类、23种具体设计模式,具体如下:

常用设计模式
针对三种设计模式类型,常见的设计模式是:
● 创建型:单例模式、工厂方法模式(及 变式)、建造者模式;
● 结构型:适配器模式、代理模式、门面(外观)模式;
● 行为型:策略模式、观察者模式

单例模式
单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供了一种全局访问点以访问该实例
饿汉式和懒汉式的区别

  1. 初始化时机不同:饿汉式单例模式在类加载时就立即初始化并创建单例对象,而懒汉式单例模式则是在第一次使用时才会进行初始化,并创建单例对象。
  2. 线程安全性不同:饿汉式单例模式在类加载时就创建了单例对象,因此天生就是线程安全的。而懒汉式单例模式在第一次使用时才会创建单例对象,如果多个线程同时调用getInstance()方法,可能会创建出多个单例对象,因此需要进行同步控制来保证线程安全。
  3. 内存占用不同:饿汉式单例模式在类加载时就创建了单例对象,因此占用的内存较多。而懒汉式单例模式在第一次使用时才会创建单例对象,因此占用的内存相对较少。
    实现方式

● 饿汉式
class Singleton {

// 1. 加载该类时,单例就会自动被创建
private static  Singleton ourInstance  = new  Singleton();

// 2. 构造函数 设置为 私有权限
// 原因:禁止他人创建实例 
private Singleton() {
}

// 3. 通过调用静态方法获得创建的单例
public static  Singleton newInstance() {
    return ourInstance;
}

}
● 懒汉式
class Singleton {

private static  Singleton ourInstance  = null;

private Singleton() {
}

public static  Singleton newInstance() {
 // 加入双重校验锁
// 校验锁1:第1个if
if( ourInstance == null){  // ①
 synchronized (Singleton.class){ // ②
  // 校验锁2:第2个 if
  if( ourInstance == null){
      ourInstance = new Singleton();
      }
  }

}

    return ourInstance;

}
}

// 说明
// 校验锁1:第1个if
// 作用:若单例已创建,则直接返回已创建的单例,无需再执行加锁操作
// 即直接跳到执行 return ourInstance

// 校验锁2:第2个 if
// 作用:防止多次创建单例问题
// 原理
// 1. 线程A调用newInstance(),当运行到②位置时,此时线程B也调用了newInstance()
// 2. 因线程A并没有执行instance = new Singleton();,此时instance仍为空,因此线程B能突破第1层 if 判断,运行到①位置等待synchronized中的A线程执行完毕
// 3. 当线程A释放同步锁时,单例已创建,即instance已非空
// 4. 此时线程B 从①开始执行到位置②。此时第2层 if 判断 = 为空(单例已创建),因此也不会创建多余的实例

● 静态内部类
原理 根据 静态内部类 的特性(外部类的加载不影响内部类),同时解决了按
需加载、线程安全的问题,同时实现简洁

  1. 在静态内部类里创建单例,在装载该内部类时才会去实例化单例
  2. 线程安全:类是由 JVM 加载,而 JVM 只会加载1遍,保证只有1个单例
    ● 枚举
    因为枚举类型是线程安全的,并且只会装载一次,设计者充分的利用了枚
    举的这个特性来实现单例模式,枚举的写法非常简单,而且枚举类型是所
    用单例实现中唯一一种不会被破坏的单例实现模式。
    为什么枚举类可以阻止反射的破坏?
    首先枚举类中是没有空参构造方法的,只有一个带两个参数的构造方法 真正原因是: 反射方法中不予许使用反射创建枚举对象
    简单工厂
    简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,其主要目的是通过将对象的创建逻辑封装在一个工厂类中,从而隐藏对象的创建细节并简 化对象的创建过程。
    在简单工厂模式中,客户端通过向工厂类传递不同的参数来请求工厂创建不同类型的对象。
    工厂方法模式
    工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了 一个用于创建对象的接口,但是具体创建哪个类的对象由子类决定。
    在工厂方法模式中,我们将对象的创建委托给具体的工厂类,由工厂类来负责创建具体的产品对象。这样,客户端代码只需要关心所需对象的抽象类型,无需关心具体的实现细节,从而实现了解耦。

代码:
public interface CarFactory {

Car getCar();

}
public class JinBeiFactory implements CarFactory {

@Override
public Car getCar() {
    return new JinBei();
}

}
public interface Car {

void carName();

}
public class JinBei implements Car {

@Override
public void carName() {
    System.out.println("金杯");
}

}
public class Customer {

public static void main(String[] args) {
    Car car = new JinBeiFactory().getCar();
    car.carName();
}

}
优缺点:
工厂方法模式的优点
用户只需要知道具体工厂的名字,就可以获取到想要的产品,不需要关注产品
的创建过程,在系统新增加产品的时候,只需要添加具体产品类和对应的具体工厂,不需要对原工厂进行修改,满足了开闭原则
工厂方法模式的缺点 :
每增加一个产品,就需要一个具体产品类和对应的具体工厂类,这样会增加系
统的复杂度
抽象工厂模式
抽象工厂模式是工厂方法模式的扩展,它不仅可以创建单一产品,还可以创建 一组相关的产品。
抽象工厂模式比工厂方法模式的抽象程度更高. 在工厂方法模式中每一个具
体工厂只需要生产一种具体产品,但是在抽象工厂模式中一个具体工厂可以
生产一组相关的具体产品,这样一组产品被称为产品族.产品族中的每一个产
品都分属于某一个产品继承等级结构.

抽象工厂模式优点

  1. 对于不同产品系列有比较多共性特征时,可以使用抽象工厂模式,有助于提
    升组件的复用性.
  2. 当需要提升代码的扩展性并降低维护成本时,把对象的创建和使用过程分
    开,能有效地将代码统一到一个级别上
  3. 解决跨平台带来的兼容性问题
    抽象工厂模式缺点
    增加新的产品等级结构麻烦,需要对原有结构进行较大的修改,甚至需要修改
    抽象层代码,这显然会带来较大不变,违背了开闭原则.
    Spring用到工厂模式的接口
    ● 1. BeanFactory:Spring中最基本的工厂模式实现是BeanFactory。BeanFactory是一个工厂类,负责创建和管理Spring应用程序中的对象。它 使用了工厂模式的思想,通过配置文件或注解来创建和管理对象。
    ● 2. ApplicationContext:ApplicationContext是BeanFactory的子接口,它是 Spring框架中更高级的工厂模式实现。它除了拥有BeanFactory的功能之 外,还提供了更多的特性,如国际化支持、事件机制、AOP、资源管理等。
    ● 3. FactoryBean:Spring还提供了FactoryBean接口,它可以用来创建特定类 型的bean。FactoryBean使用了工厂模式的思想,通过实现FactoryBean接口来创建特定类型的bean。
    ● 4. BeanPostProcessor:BeanPostProcessor是Spring框架中的另一个工厂模式实现。它负责在Spring容器实例化bean之后,对bean进行处理和修改。
    ● 5. MessageSource:Spring中的MessageSource接口也是一个工厂模式的实现。它用于国际化,通过提供一组键值对,根据本地语言和区域设置返回对 应的字符串。
    代理模式
    对一个对象提供一个代理对象,使用代理对象控制对原对象的引用。透明的控制对象的访问 , 代理模式的作用是隐藏对象的复杂性,控制对对象的访问,并在必要时增加一些额外的功能。
    静态代理与动态代理的区别
    ● 实现方式不同:
    静态代理是在编译期就已经确定代理对象的类型,代理类需要手动编写。而动 态代理是在运行时动态生成代理对象,代理类不需要手动编写,而是由框架自动生成。
    ● 适用范围不同:
    静态代理只适用于代理对象类型固定、接口较少的情况下。因为每增加一个被 代理的接口,就需要编写一个新的代理类。而动态代理则可以代理任意的接 口,无需编写新的代理类,因此更加灵活。
    ● 性能表现不同:
    由于静态代理在编译期就已经确定代理对象的类型,因此在运行时执行效率较 高。而动态代理在运行时需要进行额外的代理对象生成、方法调用转发等操 作,因此会存在一定的性能损失。

总的来说,静态代理适用于代理对象类型固定、接口较少、性能要求较高的情况。而动态代理则适用于代理对象类型不固定、接口较多、灵活性要求较高的情况
JDK动态代理与CGLIB动态代理的区别?
JDK动态代理和CGLIB动态代理是Java语言中实现动态代理的两种方式。它们之 间的主要区别如下:

  1. 基于的技术不同:JDK动态代理是基于Java的反射机制实现的,而CGLIB动态代理则是使用字节码生成技术实现的。
  2. 被代理类的要求不同:JDK动态代理只能代理实现了接口的类,而CGLIB动态代理可以代理没有实现接口的类。
  3. 代理性能不同:JDK动态代理生成的代理类性能相对较低,因为它是基于反射实现的,而CGLIB动态代理生成的代理类性能相对较高,因为它是基于字节码生成技术实现的。
  4. 代理方式不同:JDK动态代理是基于接口实现的,因此代理类必须实现被代理接口,而CGLIB动态代理是基于继承实现的,因此代理类继承被代理类。
    综上所述,JDK动态代理适合代理接口方法,而CGLIB动态代理适合代理普通类方法。如果被代理类实现了接口,那么优先选择JDK动态代理;如果被代理类没有实现接口,那么只能使用CGLIB动态代理。
    CGLIB

● 最底层是字节码
● ASM是操作字节码的工具
● cglib基于ASM字节码工具操作字节码(即动态生成代理,对方法进行增强)
● SpringAOP基于cglib进行封装,实现cglib方式的动态代理
策略模式
定义一系列算法,将每一个算法 封装起来,并使它们可以相互替换。策略模式让算法可以独立于使用它的客户端而变化。
在策略模式中可以定义一些独立的类来封装不同的算法,每一个类封装一种具体 的算法,在这里每一个封装算法的类都可以被称为一种策略,为了保证这些策略在使用时具有一致性,一般会提供一个抽象的策略类来做算法的声明.而每种算法对应一个具体的策略类。
策略模式的主要角色如下:
● 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
● 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
● 环境或上下文(Context)类:是使用算法的角色, 持有一个策略类的引 用,最终给客户端调用。
应用场景

  1. 需要根据不同的条件选择不同的算法时。例如,计算器程序需要根据用户输入的运算符选择相应的计算方法。
  2. 需要在运行时动态地选择算法时。例如,某个系统需要根据用户的配置或环境变量来选择合适的算法。
  3. 需要将算法的实现细节与客户端代码分离时。例如,某个系统需要根据不同 的数据来源来解析数据,但是客户端并不关心数据的解析细节。
    代码
    public interface Strategy {
    void algorithm();
    }
    public class ConcreteStrategyA implements Strategy {
    @Override
    public void algorithm() {

     System.out.println("执行策略A");

    }
    }
    public class ConcreteStrategyB implements Strategy {
    @Override
    public void algorithm() {

     System.out.println("执行策略B");

    }
    }

//环境类
public class Context {

//维持一个对抽象策略类的引用
private Strategy strategy;
public Context(Strategy strategy) {
    this.strategy = strategy;
}
//调用策略类中的算法
public void algorithm(){
    strategy.algorithm();
}

}

public class Client {

public static void main(String[] args) {
    Strategy strategyA = new ConcreteStrategyA();
    Context context = new Context(strategyA); //可以在运行
    时指定类型,通过配置文件+反射机制实现
    context.algorithm();
}

}
建造者模式(Builder)
将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。

建造者模式包含4个角色 :
● 抽象建造者类(Builder):这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的部件对象的创建。
● 具体建造者类(ConcreteBuilder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。在构造过程完成后,提供一个方法,返回创建好的负责产品对象。
● 产品类(Product):要创建的复杂对象 (包含多个组成部件).
● 指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指挥者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建(客户端一般只需要与指挥者进行交互)。
建造者模式与工厂模式区别
● 工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。 要把产品抽象 --> 具体产品
● 建造者模式是用来创建一种类型的复杂对象,通过设置不同的可选参数,“定制化”地创建不同的对象, 具建造者可以扩展和变更。
责任链模式
● 避免将一个请求的发送者与接收者耦合在一起,让多个对象都有机会处理请求.
● 将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止

● 将请求和请求的处理进行解耦,提高代码的可扩展性.
职责链模式主要包含以下角色:
● 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接(链上的每个处理者都有一个成员变量来保存对于下一处理者的引用,比如上图中的successor) 。
● 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
● 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
实际的开发中,并不会采用这种标准的责任链结构,而是会进行一些改变,比如增加一个责任链管理者,来管理这些具体的处理者
代码实现

//处理者接口,用于标准化执行
public interface OrderHandleIntercept {

//指定执行顺序
int sort();
//对参数进行处理
OrderContext handle(OrderContext context);

}

//创建具体处理者类,我们分别创建三个不同的接口实现类,并指定执行顺序
@Component
public class RepeatOrderHandleInterceptService implements OrderHandleIntercept {

@Override
public int sort() {return 1;//执行顺序为 1}

@Override
public OrderContext handle(OrderContext context) {
    System.out.println("通过seqId,检查客户是否重复下单");
    return context;
}

}
//还有两个类省略

//处理器链类,用于管理上面的这几个实现类
//整个针对请求的处理过程,都通过HandleChain进行管理,对于发送请求的客
//户端来说,只需要调用HandleChain,并将请求交给HandleChain处理就可以了
@Component
public class OrderHandleChainService implements ApplicationContextAware {

//保存责任链中的处理者
private List<OrderHandleIntercept> handleList = new ArrayList<>();

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

    //获取指定接口实现类,并按照sort进行排序,放入List
    //getBeansOfType这个方法能返回一个接口的全部实现类(前提是所有实现类都必须由Spring IoC容器管理)
    Map<String, OrderHandleIntercept> serviceMap = applicationContext.getBeansOfType(OrderHandleIntercept.class);
    handleList = serviceMap.values().stream()
            .sorted(Comparator.comparing(OrderHandleIntercept::sort))
            .collect(Collectors.toList());
}

//执行处理

public OrderContext execute(OrderContext context){
    for (OrderHandleIntercept handleIntercept : handleList) {
         context = handleIntercept.handle(context);
    }
    return context;
} 

}

使用场景
● 在运行时要使用多个对象对一个请求进行处理
● 不想让使用者知道具体的处理逻辑
观察者模式
观察者模式它是用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应的作出反应
在观察者模式中有如下角色:
● Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
● ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
● Observer:抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
● ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要与具体目标保持一致.
相当于观察者通过具体的方法进行注册到被观察者的一个列表中,然后观察者发生变化时,会遍历这个列表,通知到现在存活的观察者。
代码实现
//抽象观察者
public interface Observer {

//update方法: 为不同观察者的更新(响应)行为定义相同的接口,不同的观察者对该方法有不同的实现
public void update();

}

//具体观察者
public class ConcreteObserverOne implements Observer {

@Override
public void update() {
    //获取消息通知,执行业务代码
    System.out.println("ConcreteObserverOne 得到通知!");
}

}

//具体观察者
public class ConcreteObserverTwo implements Observer {

@Override
public void update() {
    //获取消息通知,执行业务代码
    System.out.println("ConcreteObserverTwo 得到通知!");
}

}
public interface Subject {

 void attach(Observer observer);
 void detach(Observer observer);
 void notifyObservers();

}

//具体目标类
public class ConcreteSubject implements Subject {

//定义集合,存储所有观察者对象
private ArrayList<Observer> observers = new ArrayList<>();

//注册方法,向观察者集合中增加一个观察者
@Override
public void attach(Observer observer) {
    observers.add(observer);
}

//注销方法,用于从观察者集合中删除一个观察者
@Override
public void detach(Observer observer) {
    observers.remove(observer);
}

//通知方法
@Override
public void notifyObservers() {
    //遍历观察者集合,调用每一个观察者的响应方法
    for (Observer obs : observers) {
        obs.update();
    }
}

}
发布订阅模式与观察者模式的区别
● 发布订阅模式属于广义上的观察者模式,发布订阅模式是最常用的一种观察者模式的实现,并且从解耦和重用角度来看,更优于典型的观察者模式
● 操作流程上的区别:
○ 观察者模式:数据源直接通知订阅者发生改变。
○ 发布订阅模式: 数据源告诉第三方(事件通道)发生了改变,第三方再通知订阅者发生了改变。
观察者模式常见的使用场景
● 一个对象的改变,需要改变其他对象的时候
● 一个对象的改变,需要进行通知的时候
适配器模式
将一个类的接口转换为客户期望的另一个接口,适配器可以让不兼容的两个类一起协同工作。适配器模式的主要作用就是把原本不兼容的接口,通过适配修改做到统一,使得用户方便使用,就想我们提到的万能充 多接口数据线等待, 他们都是为了适配各种不同的接口做的兼容。
适配器模式(Adapter)包含以下主要角色:
● 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
● 适配者(Adaptee)类:适配者即被适配的角色,它是被访问和适配的现存组件库中的组件接口。
● 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
适配器模式分为类适配器和对象适配器,两者的区别在于: 适配器与适配者的关系, 类适配器是继承关系, 对象适配器是聚合关系,根据设计原则,聚合优先于继承,应该多选用对象适配器.
实际开发中的使用
为了提升系统的速度,将一些数据以K-V 形式缓存在内存中,平台提供get,put,remove等API以及相关的管理机制.
功能实现的迭代过程,从HashMap到Memcached再到Redis,要确保后面再增加新的缓存组件时,根据配置文件能够实现自由的切换,并且还要符合开闭原则。
(1) 首先定义一个缓存接口,包含get、put、remove等操作方法。例如:
public interface Cache {

void put(String key, Object value);
Object get(String key);
void remove(String key);

}
(2) 然后实现该接口的三个适配器,分别对应HashMap、Memcached、Redis三种缓存方案。例如
public class HashMapCacheAdapter implements Cache {

private Map<String, Object> cache = new HashMap<>();

@Override
public void put(String key, Object value) {
    cache.put(key, value);
}

@Override
public Object get(String key) {
    return cache.get(key);
}

@Override
public void remove(String key) {
    cache.remove(key);
}

}
//...省略其他类
(3)使用时,只需要调用工厂类的createCacheAdapter方法,传入缓存类型即可获取相应的缓存适配器。例如
Cache cache = CacheAdapterFactory.createCacheAdapter("Redis");
cache.put("key", "value");
Object result = cache.get("key");
cache.remove("key");
适配器模式适用的场景
● 统一多个类的接口
● 原有接口无法修改时候,但是有需要兼容的时候
装饰器模式
装饰器模式在不改变原始类接口的情况下,对原始类功能进行增强,并且支持多个装饰器的嵌套使用
装饰器模式的各个角色
● Component 抽象构件角色: 是具体构件和抽象装饰类的父类,声明了具体构件中实现的业务方法,使得客户端能以一致的方式处理未装饰和已装饰对象。
● Concrete Component 具体构件角色: 是抽象构件类的子类,定义了具体的构建对象并实现了抽象构建中声明的方法。装饰类可以给它增加额外的职责(方法)。
● Decorator 抽象装饰角色: 是抽象构件类的子类,用于给具体构件增加职责,维护一个指向抽象构件对象的引用,以达到装饰的目的。
● Concrete Decorator 具体装饰角色: 是抽象装饰类的子类,负责向构件添加新的职责。每个具体装饰类都定义了一些新的行为,可以调用已定义的方法并增加新的方法。
装饰器模式和代理模式的不同
目的意图不同
● 代理模式: 控制 ---> 为了自己
● 装饰器模式: 增强 ---> 为了目标类
使用差别
● 代理模式: 对于被代理对象 有绝对的控制权,可以执行或不执行
● 装饰器模式: 没有控制权, 肯定会执行,增加了一层装饰的功能
对于客户端
● 代理模式: 更关心的是被代理对象的功能
● 装饰器模式: 更关心对于装饰器进行增强的功能
装饰器模式的适用场景
● 动态扩展功能
● 不支持继承扩展类的场景
经典场景:有多个装饰时是怎么保证后面的装饰,在前面装饰的基础上装饰的。比如字符,需要加密+压缩。怎么能让压缩,在加密的基础上压缩 ?
模板方法模式
在操作中定义算法的框架,将一些步骤推迟到子类中。模板方法让子类在不改变算法结构的情况下重新定义算法的某些步骤。模板方法中的算法可以理解为广义上的业务逻辑,并不是特指某一个实际的算法.定义中所说的算法的框架就是模板, 包含算法框架的方法就是模板方法.
模板方法(Template Method)模式包含以下主要角色:
● 抽象父类:定义一个算法所包含的所有步骤,并提供一些通用的方法逻辑。
● 具体子类:继承自抽象父类,根据需要重写父类提供的算法步骤中的某些步骤。
抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。
● 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
● 基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:
○ 抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。
○ 具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。
○ 钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。
钩子:在模板方法的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”。
钩子方法一般是空的或者有默认实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩。而要不要挂钩,又由子类去决定。
门面模式(外观模式)
定义了一个高层、统一的接口,外部与通过这个统一的接口对子系统中的一群接口进行访问。通过创建一个统一的外观类,用来包装子系统中一个 / 多个复杂的类,客户端可通过调用外观类的方法来调用内部子系统中所有方法
场景案例
小成的爷爷已经80岁了,一个人在家生活:每次都需要打开灯、打开电视、打开空调;睡觉时关闭灯、关闭电视、关闭空调;
小成买了一个智能家具控制器(外观对象/统一接口)给他爷爷,他爷爷只需要一键就能打开/关闭 灯、电视机、空调

  1. 即用外观模式来为所有子系统设计一个统一的接口
  2. 客户端只需要调用外观类中的方法就可以了,简化了客户端的操作
    应用场景
    ● 要为一个复杂的子系统对外提供一个简单的接口
    ● 提供子系统的独立性
    ● 客户程序与多个子系统之间存在很大的依赖性
    与适配器模式的区别
    ● 外观模式的实现核心主要是——由外观类去保存各个子系统的引用,实现由一个统一的外观类去包装多个子系统类,然而客户端只需要引用这个外观类,然后由外观类来调用各个子系统中的方法。
    ● 这样的实现方式非常类似适配器模式,然而外观模式与适配器模式不同的是:适配器模式是将一个对象包装起来以改变其接口,而外观是将一群对象 ”包装“起来以简化其接口。它们的意图是不一样的,适配器是将接口转换为不同接口,而外观模式是提供一个统一的接口来简化接口。

标签: none

已有 4 条评论

  1. 看的我热血沸腾啊

  2. 不错不错,我喜欢看 https://www.jiwenlaw.com/

  3. 叼茂SEO.bfbikes.com

  4. 不错不错,我喜欢看 www.jiwenlaw.com

添加新评论