Android Gradle Plugin 源码解析(上)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 一、源码依赖本文基于:android gradle plugin版本:com.android.tools.build:gradle:2.

一、源码依赖

本文基于:

android gradle plugin版本:

com.android.tools.build:gradle:2.3.0

gradle 版本:4.1

Gradle源码总共30个G,为简单起见,方便大家看源码,此处通过gradle依赖的形式来查看源码,依赖源码姿势:

创建一个新工程,app 项目目录中删除所有文件,仅留下gradle文件,依赖

apply plugin: 'java'
sourceCompatibility = 1.8
dependencies {
 compile gradleApi()
 compile 'com.android.tools.build:gradle:2.3.0'
}

将跟目录下的gradle文件,删除掉gradle依赖

buildscript {
 repositories {
 google()
 jcenter()
 }
 dependencies {
// compile 'com.android.tools.build:gradle:2.3.0'
 }
}

然后rebuild一下,就可以在External Libraries中查看到android gradle的源码已经依赖了

二、Android Gradle Plugin简介

我们知道Android gradle plugin是用来构建Android工程的gradle插件,在Android gradle 插件中,可以看到app工程和library工程所依赖的plugin是不一样的

// app 工程
apply plugin: 'com.android.application'
// library 工程
apply plugin: 'com.android.library'

而对应填写andorid块中所填写的配置也不同,这就是区分Application和Library的插件的extension块

分别为:

app工程 -> AppPlugin -> AppExtension
librar工程 -> LibraryPlugin -> LibraryExtension

对应的是AppPlugin和AppExtension,这两个插件构建的流程大抵是相同的,只是各自插件生成的任务不同,接下来我们着重分析Application插件是如何构建我们的Android应用的

三、AppPlugin的构建流程

我们先看下app工程中gradle的文件格式

apply plugin: 'com.android.application'
android {
 compileSdkVersion 25
 buildToolsVersion '26.0.2'
 defaultConfig {
 applicationId "com.zengshaoyi.gradledemo"
 minSdkVersion 15
 targetSdkVersion 25
 versionCode project.ext.versionCode
 versionName project.ext.versionName
 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
 }
 buildTypes {
 release {
 minifyEnabled false
 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
 }
 }
 lintOptions {
 abortOnError false
 }
}

跟踪apply方法,其实是进入到

AppPlugin的apply的方法,我们可以看到内部实现是直接调用父类BasePlugin的apply方法

protected void apply(@NonNull Project project) {
 checkPluginVersion();
 this.project = project;
 ExecutionConfigurationUtil.setThreadPoolSize(project);
 checkPathForErrors();
 checkModulesForErrors();
 ProfilerInitializer.init(project);
 threadRecorder = ThreadRecorder.get();
 ProcessProfileWriter.getProject(project.getPath())
 .setAndroidPluginVersion(Version.ANDROID_GRADLE_PLUGIN_VERSION)
 .setAndroidPlugin(getAnalyticsPluginType())
 .setPluginGeneration(GradleBuildProject.PluginGeneration.FIRST);
 threadRecorder.record(
 ExecutionType.BASE_PLUGIN_PROJECT_CONFIGURE,
 project.getPath(),
 null,
 this::configureProject);
 threadRecorder.record(
 ExecutionType.BASE_PLUGIN_PROJECT_BASE_EXTENSION_CREATION,
 project.getPath(),
 null,
 this::configureExtension);
 threadRecorder.record(
 ExecutionType.BASE_PLUGIN_PROJECT_TASKS_CREATION,
 project.getPath(),
 null,
 this::createTasks);
 // Apply additional plugins
 for (String plugin : AndroidGradleOptions.getAdditionalPlugins(project)) {
 project.apply(ImmutableMap.of("plugin", plugin));
 }
 }

threadRecoirder.recode()是记录最后一个参数的路径和执行的时间点,前面做了一些必要性的信息检测之前,其实主要做了以下几件事情:

// 配置项目,设置构建回调
this::configureProject
// 配置Extension
this::configureExtension
// 创建任务
this::createTasks

::是java 8引入的特性,详情可以查看java8特性 ,这里就是方法的调用

configureProject

直接来看源码

private void configureProject() {
 extraModelInfo = new ExtraModelInfo(project);
 checkGradleVersion();
 AndroidGradleOptions.validate(project);
 // Android SDK处理类
 sdkHandler = new SdkHandler(project, getLogger());
 // 设置项目评估阶段回调
 project.afterEvaluate(p -> {
 // TODO: Read flag from extension.
 if (!p.getGradle().getStartParameter().isOffline()
 && AndroidGradleOptions.getUseSdkDownload(p)) {
 // 相关配置依赖的下载处理 
 SdkLibData sdkLibData =
 SdkLibData.download(getDownloader(), getSettingsController());
 dependencyManager.setSdkLibData(sdkLibData);
 sdkHandler.setSdkLibData(sdkLibData);
 }
 });
 // 创建AndroidBuilder
 androidBuilder = new AndroidBuilder(
 project == project.getRootProject() ? project.getName() : project.getPath(),
 creator,
 new GradleProcessExecutor(project),
 new GradleJavaProcessExecutor(project),
 extraModelInfo,
 getLogger(),
 isVerbose());
 // dataBinding的相关处理
 dataBindingBuilder = new DataBindingBuilder();
 dataBindingBuilder.setPrintMachineReadableOutput(
 extraModelInfo.getErrorFormatMode() ==
 ExtraModelInfo.ErrorFormatMode.MACHINE_PARSABLE);
 // Apply the Java and Jacoco plugins.
 project.getPlugins().apply(JavaBasePlugin.class);
 project.getPlugins().apply(JacocoPlugin.class);
 // 给assemble任务添加描述
 project.getTasks()
 .getByName("assemble")
 .setDescription(
 "Assembles all variants of all applications and secondary packages.");
 ...

可以看到 configureProject 方法中在 project.afterEvaluate 设置了回调,当项目评估结束时,根据项目配置情况,设置 dependece 依赖;创建了 AndroidBuilder 对象,这个对象是用来合并manifest 和创建 dex 等作用,后面在创建任务的过程中会使用到,结下来继续看 configureProject 的源码

 // call back on execution. This is called after the whole build is done (not
 // after the current project is done).
 // This is will be called for each (android) projects though, so this should support
 // being called 2+ times.
 // 设置构建回调
 project.getGradle()
 .addBuildListener(
 new BuildListener() {
 private final LibraryCache libraryCache = LibraryCache.getCache();
 @Override
 public void buildStarted(Gradle gradle) {}
 @Override
 public void settingsEvaluated(Settings settings) {}
 @Override
 public void projectsLoaded(Gradle gradle) {}
 @Override
 public void projectsEvaluated(Gradle gradle) {}
 @Override
 public void buildFinished(BuildResult buildResult) {
 ExecutorSingleton.shutdown();
 sdkHandler.unload();
 threadRecorder.record(
 ExecutionType.BASE_PLUGIN_BUILD_FINISHED,
 project.getPath(),
 null,
 () -> {
 // 当任务执行完成时,清楚dex缓存
 PreDexCache.getCache()
 .clear(
 FileUtils.join(
 project.getRootProject()
 .getBuildDir(),
 FD_INTERMEDIATES,
 "dex-cache",
 "cache.xml"),
 getLogger());
 JackConversionCache.getCache()
 .clear(
 FileUtils.join(
 project.getRootProject()
 .getBuildDir(),
 FD_INTERMEDIATES,
 "jack-cache",
 "cache.xml"),
 getLogger());
 libraryCache.unload();
 Main.clearInternTables();
 });
 }
 });
 // 设置创建有向图任务回调
 project.getGradle()
 .getTaskGraph()
 .addTaskExecutionGraphListener(
 taskGraph -> {
 for (Task task : taskGraph.getAllTasks()) {
 // TransformTask是class编译成dex的重要任务
 if (task instanceof TransformTask) {
 Transform transform = ((TransformTask) task).getTransform();
 if (transform instanceof DexTransform) {
 PreDexCache.getCache()
 .load(
 FileUtils.join(
 project.getRootProject()
 .getBuildDir(),
 FD_INTERMEDIATES,
 "dex-cache",
 "cache.xml"));
 break;
 } else if (transform instanceof JackPreDexTransform) {
 JackConversionCache.getCache()
 .load(
 FileUtils.join(
 project.getRootProject()
 .getBuildDir(),
 FD_INTERMEDIATES,
 "jack-cache",
 "cache.xml"));
 break;
 }
 }
 }
 });

这里在添加了 BuildListener,在 buildFinished 的时候清楚了dex缓存,而在任务有向图创建的回调中,判断是否是 DexTransfrom,从而从缓存中加载dex。

总结一下 configureProject 做的事情,主要是进行版本有效性的判断,创建了 AndroidBuilder 对象,并设置了构建流程的回调来处理依赖和dex的加载和缓存清理。

configureExtension

这个阶段就是配置 extension 的阶段,就是创建我们 android 块中的可配置的对象

private void configureExtension() {
 final NamedDomainObjectContainer<BuildType> buildTypeContainer =
 project.container(
 BuildType.class,
 new BuildTypeFactory(instantiator, project, project.getLogger()));
 final NamedDomainObjectContainer<ProductFlavor> productFlavorContainer =
 project.container(
 ProductFlavor.class,
 new ProductFlavorFactory(
 instantiator, project, project.getLogger(), extraModelInfo));
 final NamedDomainObjectContainer<SigningConfig> signingConfigContainer =
 project.container(SigningConfig.class, new SigningConfigFactory(instantiator));
 extension =
 createExtension(
 project,
 instantiator,
 androidBuilder,
 sdkHandler,
 buildTypeContainer,
 productFlavorContainer,
 signingConfigContainer,
 extraModelInfo);
 ...

首先创建了 BuildType、ProductFlavor、SigningConfig 三个类型的Container,接着传入到了createExtension方法中,点入查看是个抽象的方法,各自的实现在子类中,这里也就是我们的AppPlugin 中

@NonNull
 @Override
 protected BaseExtension createExtension(
 @NonNull Project project,
 @NonNull Instantiator instantiator,
 @NonNull AndroidBuilder androidBuilder,
 @NonNull SdkHandler sdkHandler,
 @NonNull NamedDomainObjectContainer<BuildType> buildTypeContainer,
 @NonNull NamedDomainObjectContainer<ProductFlavor> productFlavorContainer,
 @NonNull NamedDomainObjectContainer<SigningConfig> signingConfigContainer,
 @NonNull ExtraModelInfo extraModelInfo) {
 return project.getExtensions()
 .create(
 "android",
 AppExtension.class,
 project,
 instantiator,
 androidBuilder,
 sdkHandler,
 buildTypeContainer,
 productFlavorContainer,
 signingConfigContainer,
 extraModelInfo);
 }

这里也就是可以看到我们android块配置是如何来的了,对应的Extension也确实是AppExtension,继续查看 configureExtension 的源码

 dependencyManager = new DependencyManager(
 project,
 extraModelInfo,
 sdkHandler);
 ndkHandler = new NdkHandler(
 project.getRootDir(),
 null, /* compileSkdVersion, this will be set in afterEvaluate */
 "gcc",
 "" /*toolchainVersion*/);
 taskManager =
 createTaskManager(
 project,
 androidBuilder,
 dataBindingBuilder,
 extension,
 sdkHandler,
 ndkHandler,
 dependencyManager,
 registry,
 threadRecorder);
 variantFactory = createVariantFactory(instantiator, androidBuilder, extension);
 variantManager =
 new VariantManager(
 project,
 androidBuilder,
 extension,
 variantFactory,
 taskManager,
 instantiator,
 threadRecorder);
 // Register a builder for the custom tooling model
 ModelBuilder modelBuilder = new ModelBuilder(
 androidBuilder,
 variantManager,
 taskManager,
 extension,
 extraModelInfo,
 ndkHandler,
 new NativeLibraryFactoryImpl(ndkHandler),
 getProjectType(),
 AndroidProject.GENERATION_ORIGINAL);
 registry.register(modelBuilder);
 // Register a builder for the native tooling model
 NativeModelBuilder nativeModelBuilder = new NativeModelBuilder(variantManager);
 registry.register(nativeModelBuilder);

这一部分主要是创建一些管理类,其中 createTaskManager、createVariantFactory 都是抽象方法,对应的实现类

createTaskManager
AppPlugin -> ApplicationTaskManager
LibraryPlugin -> LibraryTaskManager
createVariantFactory
AppPlugin -> ApplicationVariantFactory
LibraryPlugin -> LibraryVariantFactory

这里简单介绍一下 TaskManager 就是创建具体任务的管理类,app 工程和库 library 工程所需的构建任务是不同的,后面我们会介绍 app 工程创建的构建任务;VariantFactory 就是我们常说的构建变体的工厂类,主要是生成Variant(构建变体)的对象。我们回到 createExtension 的源码中

 // map the whenObjectAdded callbacks on the containers.
 signingConfigContainer.whenObjectAdded(variantManager::addSigningConfig);
 buildTypeContainer.whenObjectAdded(
 buildType -> {
 SigningConfig signingConfig =
 signingConfigContainer.findByName(BuilderConstants.DEBUG);
 buildType.init(signingConfig);
 variantManager.addBuildType(buildType);
 });
 productFlavorContainer.whenObjectAdded(variantManager::addProductFlavor);
 ...
 // create default Objects, signingConfig first as its used by the BuildTypes.
 variantFactory.createDefaultComponents(
 buildTypeContainer, productFlavorContainer, signingConfigContainer);

这一部分做得事情,配置了 BuildTypeContainer、ProductFlavorContainer、SigningConfigContainer 这三个配置项的 whenObjectAdded 的回调,每个配置的添加都会加入到 variantManager 中;创建默认配置,下面是 ApplicationVariantFactory 的 createDefaultComponents 代码

 @Override
 public void createDefaultComponents(
 @NonNull NamedDomainObjectContainer<BuildType> buildTypes,
 @NonNull NamedDomainObjectContainer<ProductFlavor> productFlavors,
 @NonNull NamedDomainObjectContainer<SigningConfig> signingConfigs) {
 // must create signing config first so that build type 'debug' can be initialized
 // with the debug signing config.
 signingConfigs.create(DEBUG);
 buildTypes.create(DEBUG);
 buildTypes.create(RELEASE);
 }

总结一下 configureExtension 方法的作用,主要是创建 Android 插件的扩展对象,对配置项 BuildType、ProductFlavor、SigningConfig 做了统一的创建和回调处理, 创建taskManager、variantFactory、variantManager。

createTasks

private void createTasks() {
 threadRecorder.record(
 ExecutionType.TASK_MANAGER_CREATE_TASKS,
 project.getPath(),
 null,
 () -> // 在项目评估之前创建任务 
 taskManager.createTasksBeforeEvaluate(
 new TaskContainerAdaptor(project.getTasks())));
 project.afterEvaluate(
 project ->
 threadRecorder.record(
 ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS,
 project.getPath(),
 null,
 // 在项目评估完成之后创建 androidTask
 () -> createAndroidTasks(false)));
 }

这里主要是分两块,一个是在 beforeEvaluate 创建任务;一个是在 afterEvaluate 创建任务。这里的区别是 AndroidTask 是依赖配置项的配置才能生成相应任务,所以是需要在 afterEvaluate 之后创建,如果对项目评估回调不理解的话,可以查阅Project文档。beforeEvaluate 创建的任务跟我们编译没有太大关系,我们重点查看一下 afterEvaluate 创建的任务 createAndroidTasks

 @VisibleForTesting
 final void createAndroidTasks(boolean force) {
 ...
 threadRecorder.record(
 ExecutionType.VARIANT_MANAGER_CREATE_ANDROID_TASKS,
 project.getPath(),
 null,
 () -> {
 // 创建AndroidTasks
 variantManager.createAndroidTasks();
 ApiObjectFactory apiObjectFactory =
 new ApiObjectFactory(
 androidBuilder, extension, variantFactory, instantiator);
 for (BaseVariantData variantData : variantManager.getVariantDataList()) {
 apiObjectFactory.create(variantData);
 }
 });
 ...
 }

我们主要看下variantManager的createAndroidTasks的方法

 /**
 * Variant/Task creation entry point.
 *
 * Not used by gradle-experimental.
 */
 public void createAndroidTasks() {
 variantFactory.validateModel(this);
 variantFactory.preVariantWork(project);
 final TaskFactory tasks = new TaskContainerAdaptor(project.getTasks());
 if (variantDataList.isEmpty()) {
 recorder.record(
 ExecutionType.VARIANT_MANAGER_CREATE_VARIANTS,
 project.getPath(),
 null /*variantName*/,
 this::populateVariantDataList);
 }
 // Create top level test tasks.
 recorder.record(
 ExecutionType.VARIANT_MANAGER_CREATE_TESTS_TASKS,
 project.getPath(),
 null /*variantName*/,
 () -> taskManager.createTopLevelTestTasks(tasks, !productFlavors.isEmpty()));
 for (final BaseVariantData<? extends BaseVariantOutputData> variantData : variantDataList) {
 recorder.record(
 ExecutionType.VARIANT_MANAGER_CREATE_TASKS_FOR_VARIANT,
 project.getPath(),
 variantData.getName(),
 () -> createTasksForVariantData(tasks, variantData));
 }
 taskManager.createReportTasks(tasks, variantDataList);
 }

首先判断 variantDataList 是否是空,如果是空的就会进入到 populateVariantDataList 方法中

/**
 * Create all variants.
 */
 public void populateVariantDataList() {
 if (productFlavors.isEmpty()) {
 createVariantDataForProductFlavors(Collections.emptyList());
 } else {
 List<String> flavorDimensionList = extension.getFlavorDimensionList();
 // Create iterable to get GradleProductFlavor from ProductFlavorData.
 Iterable<CoreProductFlavor> flavorDsl =
 Iterables.transform(
 productFlavors.values(),
 ProductFlavorData::getProductFlavor);
 // Get a list of all combinations of product flavors.
 List<ProductFlavorCombo<CoreProductFlavor>> flavorComboList =
 ProductFlavorCombo.createCombinations(
 flavorDimensionList,
 flavorDsl);
 for (ProductFlavorCombo<CoreProductFlavor> flavorCombo : flavorComboList) {
 //noinspection unchecked
 createVariantDataForProductFlavors(
 (List<ProductFlavor>) (List) flavorCombo.getFlavorList());
 }
 }
 }

从方法注释可以看到,这个方法主要的作用就是创建所有的 variants,试想一下该段代码会做哪些事情,是否是解析 buildType、productFlavor 配置?

创建构建变体(BuildVariant)

继续观察上面的代码,可以看到无论是否有配置productFlavor 子项,都会进入到 createVariantDataForProductFlavors 方法。如果有配置的话,通过获取配置的 flavorDimension 和 productFlavor 数组,调用 ProductFlavorCombo.createCombinations 组合出最后的产品风味数组 flavorComboList ,最后通过遍历调用 createVariantDataForProductFlavors 方法

 /**
 * Creates VariantData for a specified list of product flavor.
 *
 * This will create VariantData for all build types of the given flavors.
 *
 * @param productFlavorList the flavor(s) to build.
 */
 private void createVariantDataForProductFlavors(
 @NonNull List<ProductFlavor> productFlavorList) {
 ...
 for (BuildTypeData buildTypeData : buildTypes.values()) {
 boolean ignore = false;
 ...
 if (!ignore) {
 BaseVariantData<?> variantData = createVariantData(
 buildTypeData.getBuildType(),
 productFlavorList);
 variantDataList.add(variantData);
 ...
 }
 }
 ...
}

看上述代码,通过 creatVariantData 方法,将 buildType 和 productFlavor 的作为参数传入,创建了 variantData,并且加入到了 variantDataList 集合中,这里我们就是将所有的构建变体集合到了 variantDataList 中。

接着我们返回继续看 createAndroidTasks 方法

 /**
 * Variant/Task creation entry point.
 *
 * Not used by gradle-experimental.
 */
 public void createAndroidTasks() {
 ...
 for (final BaseVariantData<? extends BaseVariantOutputData> variantData : variantDataList) {
 recorder.record(
 ExecutionType.VARIANT_MANAGER_CREATE_TASKS_FOR_VARIANT,
 project.getPath(),
 variantData.getName(),
 () -> createTasksForVariantData(tasks, variantData));
 }
 ...
 }

通过上面拿到的variantDataList,遍历该集合来创建任务

 /**
 * Create tasks for the specified variantData.
 */
 public void createTasksForVariantData(
 final TaskFactory tasks,
 final BaseVariantData<? extends BaseVariantOutputData> variantData) {
 final BuildTypeData buildTypeData = buildTypes.get(
 variantData.getVariantConfiguration().getBuildType().getName());
 if (buildTypeData.getAssembleTask() == null) {
 // 创建assemble + buildType任务
 buildTypeData.setAssembleTask(taskManager.createAssembleTask(tasks, buildTypeData));
 }
 // Add dependency of assemble task on assemble build type task.
 tasks.named("assemble", new Action<Task>() {
 @Override
 public void execute(Task task) {
 assert buildTypeData.getAssembleTask() != null;
 // 将 assemble 任务依赖于我们的 assemble + buildType 任务
 task.dependsOn(buildTypeData.getAssembleTask().getName());
 }
 });
 VariantType variantType = variantData.getType();
 // 根据 variantData 创建 assemble + flavor + buildType 任务
 createAssembleTaskForVariantData(tasks, variantData);
 if (variantType.isForTesting()) {
 ...
 } else {
 // 根据 variantData 创建一系列任务
 taskManager.createTasksForVariantData(tasks, variantData);
 }
 }

首先会先根据 buildType 信息创建 assemble + buildType 的任务,可以看下taskManager. createAssembleTask里的代码

 @NonNull
 public AndroidTask<DefaultTask> createAssembleTask(
 @NonNull TaskFactory tasks,
 @NonNull VariantDimensionData dimensionData) {
 final String sourceSetName =
 StringHelper.capitalize(dimensionData.getSourceSet().getName());
 return androidTasks.create(
 tasks,
 // 设置任务名字为 assembleXXX
 "assemble" + sourceSetName,
 assembleTask -> {
 // 设置描述和任务组
 assembleTask.setDescription("Assembles all " + sourceSetName + " builds.");
 assembleTask.setGroup(BasePlugin.BUILD_GROUP);
 });
 }

创建完任务之后,将assemble任务依赖于我们的assembleXXX任务,随后调用 createAssembleTaskForVariantData 方法,此方法是创建 assemble + flavor + buildType 任务,流程多了 productFlavor 任务的创建,这里就不赘述了。后面会执 createTasksForVariantData,这个方法就是根据 variant 生成一系列 Android 构建所需任务(后面会详细介绍),回到 createAndroidTasks 方法中

threadRecorder.record(
 ExecutionType.VARIANT_MANAGER_CREATE_ANDROID_TASKS,
 project.getPath(),
 null,
 () -> {
 variantManager.createAndroidTasks();
 ApiObjectFactory apiObjectFactory =
 new ApiObjectFactory(
 androidBuilder, extension, variantFactory, instantiator);
 for (BaseVariantData variantData : variantManager.getVariantDataList()) {
 // 创建variantApi,添加到extensions中
 apiObjectFactory.create(variantData);
 }
 });

最后就遍历 variantDataList 通过 ApiObjectFactory 创建 variantApi,添加到 extensions 中。至此,我们就已经将配置的构建变种任务已经添加到我们的任务列表中,并形成了相关依赖。
    一篇文太长,还有一半下一章发出来。

最后

感谢你到这里,喜欢的话请帮忙点个赞让更多需要的人看到哦。更多Android进阶技术,面试资料整理分享,职业生涯规划,产品,思维,行业观察,谈天说地。可以加Android架构师群;701740775。

相关文章
|
1月前
|
Java 开发工具 Android开发
Android与iOS开发环境搭建全解析####
本文深入探讨了Android与iOS两大移动操作系统的开发环境搭建流程,旨在为初学者及有一定基础的开发者提供详尽指南。我们将从开发工具的选择、环境配置到第一个简单应用的创建,一步步引导读者步入移动应用开发的殿堂。无论你是Android Studio的新手还是Xcode的探索者,本文都将为你扫清开发道路上的障碍,助你快速上手并享受跨平台移动开发的乐趣。 ####
|
4天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
4天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
4天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
26天前
|
存储 Linux API
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。
|
28天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
55 12
|
23天前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
5天前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
Plugin is too old, please update to a more recent version, or set ANDROID_DAILY_OVERRIDE environment variable to “*****”
Plugin is too old, please update to a more recent version, or set ANDROID_DAILY_OVERRIDE environment variable to “*****”  的一种解决方案:   修改工程依赖的build.
1089 0
|
22天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
46 19

推荐镜像

更多