软件开发的六大规划准则
开闭准则
对扩展打开,对修改封闭。其目的在于当咱们需求拓宽一个功用的时分,不能去修改原有的代码,而应该去通过其它的办法jetbrains官网来到达这个目的,其实此处的其它办法,便是针对代码中容易发生改动的位子,使用接口或笼统类来进行拓宽,在需求改动的时分,只需求依据需求从头派生一个新的结束类就能够了。
里氏代换准则
任何基类能够出现的当地,子类必定能够出现。这就要求,子类jetbrains什么意思能够结束父类中的笼统办法,但不要掩盖父类已结束的办法。假定随意修改了父类已结束的办法,或许会带来未知的过错。
依托倒置准则
高层模块不应该依托低层模块,两者都应该依托其笼统;笼统不应该依托细节,细节应该依托笼统。其中心思想是:面向接口编程
单一职责
一个政策,一个模块功用应该是单一的,不应该承当太多的职责,也便是术业有专攻。
接口隔绝准则
- 客户端不应该依托它不需求的接口
- 类间的依托联络应该建立在最小的接口上
假定一个类结束一个接口,但这个接口中有它不需求的办法,那么就需求把这个接口拆分,把它需求的办法提取出来,组成一个新的接口让这个类去结束,这便是接口隔绝准则。简而言之,便是说,接口中的悉数办法对其结束的子类都是有用的。否则,就将接口持续细分。
迪米特规矩
也叫最少知道准则(Least Knowledgit教程ge Principle
)一个类应该对其它的政策有最少的了解。
- 从依托者的视点来说,只依托其应该依托的政策
- 从jetbrains idea被依托者的视点来讲,只显露该显露的办法
组成复用准则
在软件规划的时分Android应该优先选用组合,其次才考虑运用承继联络
软件开发的六大规划准则从一个高维度进行教导软件开发的实践,为开发可保护,高拓宽性软件龚俊提供办法论。
Android组件化
许多时分,当咱们架构说到组件化时,有人会说到模块化。那么模块架构是什么意思化和组件化到底有什么差异和联络呢?有的文章或书上介绍到:
- 组件是从功用的视点上去差异,如同享组件,路由组件,图片加载组件。
- 模块是从事务的视点上去差异,如主页模块,订单模块,个人中心模块。
可是你宫颈癌疫苗会发现互联网上他人在谈组件化的时分,会giti是什么牌子把上面说到的路由,订单模块都称作为组件了。这儿咱们就不去字斟句酌了,我这篇总结里约好组件和模块是同一个东西。
再回到咱们开发的进程中来,假定是一个项目从头开端开发,或许做了没两天就会碰到这giti种状况,代码里边没有一起的dialog控件,然后leader 就会说:xx, 你封装一个一起的dgoogleialog组件吧。过段时刻发现没有一起的上拉加载列表控件,然后leader又说:xxgiti轮胎,你整一个列表组架构设计件吧…
两年过去了,项目中的代码越来越多了,参与的人员越来越多了,由本架构图用什么软件做来的一个团队扩展成多个团架构队协作开狗狗币发,扯皮的事也越来越多了,编译jetbrains idea时刻也从本来的20s到现在狗狗币的3分钟了。所以咱们开端吐槽了:
- 其他团队的伙伴又改了我这个类的代码,导致我这边犯错宫颈癌前期症状
- 登录模块和个人中心一两年没有动过了,能不能这一部份代码抽出去,打个aar,咱们编译也能提速
- 我首要做基础android平板电脑价格UI控件google支撑的,改下代码还要下载你们的项目,编译,太耗时了。我就想只调试我写的UI控件。
- …
咱们架构师和程序员的差异来总结以上项目迭代进程中的痛点:
- 各事务线架构设计耦合太紧,开发进程涉及到相互依托的功用时,会有犯错风险
- 部份安稳功用,长jetbrains idea时刻没有迭代,但因为都在同一个jetbrains是什么软件库了,会拉长编译时刻
- 部份功用想独自作业
- …
悉数的问题终究抛到leader这儿github来,所以排了一堆的技改需求:
- 项目按
主页
,产品
,订单
,个人中心
,登录
几个事务模块来分module
开发,module
之架构图间不相互依托, 一起收紧代码权限,这样不同团队之间就不会存在代码抵触的问题 -
登录
这个现gitlab已安稳的模块,近期不会有改动,可直接打成aar包供其它团队引进运用 - 独自界说一架构图制造个module, 命名为
ui
, 整个工程中的基础UI控件,悉数都放到这儿来 - 界说一个module名为
common
, 为项目android体系提供一些公共的事务资源,被其它事务模块所依托 - 界说一个一起的内部路由,供各个组件间进行相互跳转
- …
所以,咱们能够看到,giti轮胎在这一堆的技git教程改结束后,整个工程便分为了多个module
, 每一个的功用更加的单一,每个人/每个团队专心于自己的作业,也少了许多扯皮的作业,一起每一个团队都能够依据自己的事务开展实际状况,选jetbrains怎样读择自己希望的技能栈。以上这些作业结束了,一个组件化的架构雏形便出来了。
咱们再来细看一个组件化架构要处理哪些问题:
- 每个组件既能够是一个组件,也能够是一个application,能够独自打包调试
- 组件间的通讯
- 组件间资源抵触的问题
- 组件间的跳转
module和app人物的切换
manifest文件
咱们希望每一个事务子module,通过装备,工商银行能够独自作业起来,此刻就涉及到manifest的装备了。默认状况下,每一个module都只会有一个manifest文件,在打包阶段,android平板电脑价格打包东西会将每个moduAndroidle中的manifestgithub文件合并,构成整个项目的mani架构图fest文件。比如,关于个人中心
module, 它里边有一个activity名为PersonaMainActivity
当它造android什么意思作一个app作业起来的时分, 该android体系activity是运用的进口,jetbrains官网下载为此,在对android下载应的manifest中会有相似如下代码:
<activity android:name=".vi架构师薪酬一月多少ew.PersonalMainActivity"&android体系gt;
<intent-filter&ggooglet;
<action android:name="android.intentandroid是什么手机牌子.action.MAIN" />
<categorjetbrains官网下载y android:name="android.宫崎骏intent.category.LAUNCHER" />
</intent架构是什么意思-filter>
</activity>
可是,项目在发版的时分,个人中心
这个模块必定是作为一个子module引进来的,PersonalMainActivity
绝对不或许是整个app的进口。为此咱们需求界说两套不同的manifest文件,一套是当该组件做为app作业的时选用,另一套是当该组件做为module时选用。
咱们在项目的根目录界说一个文件config.gradle
, 里边界说一个变量moduleAsApp
, 当该值为false
时,代表该项目中悉数的事务子module都作为组件android平板电脑价格被主mo架构图用什么软件做dule依托,当它为true
时,代表事务子module可作为jetbrains-agent.jar怎样用独立apgit教程p作业。然后在每一个giti是什么牌子事务子module中都引进该装备。
config.gradle
文件:jetbrains-agent.jar怎样用
ext {
moduleAsApp = false;
appId = [
"app" :github中文官网网页 "com.fred.routerapp",
"order" : "com.fred.order",
"product" : "cojetbrains官网m.fred.product",
"personal" : "co狗狗币m.fred.personal架构师薪酬一月多少"
]
packageNameForAPT = appId宫颈癌.app + ".apt";
a架构师ndroidConfig = [
compileSdkVersion: 29,
buildToolsVergooglesion: "29.0.3",
minSdkVersion : 21,
targetSdkVersion : 29,
versionCode : 1,
versio架构是什么意思nName : "1.0"
]
}
再回到咱们的个人中心moduandroid什么意思le里边来,对这两宫颈癌疫苗种状况分别选用不同狗狗币的manandroid手机ifest文件,如下:
sourceSets {
main {
if (moduleAsApp) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml架构图用什么软件做'
} elgiti轮胎se {
manijetbrains官网下载feJetBrainsst.srcFile 'src/main/AndroidManifest.xml'
java {
// release 时 debug 目录下文件不需求合并到主工程
exclude '**/git教程debug/**'
}
}
}
}
关于module装备和jetbrains是什么软件applicationId
if (moduleAsApp) {
apply plugin: 'com.android.application'
} else {
apply plugi狗狗币n: 'candroid手机om.android.lib公积金rary'
}
applicationId:
if (moduleAsApp) {
applicationId appId.personal
}
资源名抵触
在组件化开发进程中,或许会存在资源名抵触的问题,假定在product模块中有一个price_degiteetail.xml
用来显现价格相关宫颈癌的视图,在o架构师需求把握哪些常识rder
模块中也有一个price_detail.git指令xml
,那便会出现资源名抵触。关于这种问题,能够一起命名办法,如加前缀,android什么意思将product
模块中的这些资源命名悉数加上product_
前缀,ordgit教程er
模块中悉数加上order_
前缀,这样能够必定程序上防止。当然假定仅仅针关于布局xml文件能够在gradlandroid是什么手机牌子e文件中进行装备来束缚
android {
...
resourcePrefix "personal"
...
}
这种办法并不是说在编译的时分会手动将你的文件名进行修改,加personal_
的前缀。仅仅加了这个装备,假定你的命名不合法,编译器会给一个提示。
关于资源命名抵触这一块咱们不只需求jetbrains什么意思重视布架构图制造局文件,还有相似于color,angiti轮胎im, dimen等命名
组件间的通讯
此处组件间的通讯首要包括两方面的内容:一种是事务之间的告诉消息,比如订单模块中,一个订单提交了,需求告诉购物车改写一个购物车中的产品列表,关于这种类型的消息告诉,咱们能够选用EventBus,RxBus这种消息总线来做google。另一个通讯则是组件间基础数据的打通。比如在订单模块中,用户下单时需求判别是否登录,从单一职责的原android12则上讲用户的登录信息是在个人中心模块中才有。那么个人中心模块怎样向其它模块提供用户相关的数据呢?
还记得咱们前面说到android12的common
module吗?它能够被其它的悉数事务子android12模块依托,所以咱们在common
module中界说一个接口IAccountService
public interface IAc架构是什么意思countServ宫颈癌ice {
public架构师需求把握哪些常识 boolean isLandroid下载安装ogin();
...
}
在个人中心模块有它的结束类
pugitiblic class AccountServiceImpl implements IAccogoogleuntService {
@Override
public boolean isLogin() {
return false;
}
}
在common
模块中有一个ServiceManager
类,这个类是一个服务的处理者,它会持有一个AccountService
, 如下:
public class ServiceManag架构图制造er {
private ServiceManager() {}
prandroid手机ivate IAccountService accountService;
private static class AppConfigurationHolder {
private static f架构inal ServiceManaggiti是什么牌子er instance = new ServiceManager();
}
public static ServiceManager getInstance() {
return AppConfiguratiGitonHolder.instance;
}
public void setAcgithubcountService(IAccounAndroidtService as) {jetbrains idea
this.accountService = as;
}
public IAccountService getAccountService() {
return this.ajetbrains-agent.jar怎样用ccountService;
}
}
咱们希望其它模块经Go过调用ServiceMa架构是什么意思nager.getInstance().getAccountService()
便能够拿到用户信息相关的服务。假定要到达此目的,那这个AcccountService
在什么时分注入呢?咱们在再看app的架构依托
AccountService
的结束在个人中心modul宫颈癌前期症状e,咱们不确定用户在什么场景会调jetbrains激活码用这个服务。关于架构师这种类型的服务,需求在app发起的时分便注入到app中。而AccountService
只能在个人中心模giti是什么牌子块实例化,为此个人中心模块有必要要能监听到运用的初始化机会,git教程也便是Application的onCreate
办法
监听Application的状况
在common
组件中界说一个接口, 其它的事务module都会完枸杞结这个接口。
public interface AppStateListener {
void onCreate();
void onLowMemory();
}
在个人中心模块会有一个类, 在onCreate
中会new
一个github永久回家地址Accoun架构图制造tSandroid的drawable类ervice
,而且注入到ServiceManager
中
public class PersonalAppStatusListener implements AppStateListener {
@Override
pjetbrains-agent.jar怎样用ublic void onCreategit指令() {
ServiceManager.getInstance().setAccountService(new AccountServiceImpl(AppStateManager.getIgiteenstance().getA工商银行pplication()));
}
@Override
public void on架构师需求把握哪些常识LowMemory() {
}
}
在common
模块中,会有一个类来保护悉数的子事务module对Application状况jetbrains中文版的监听
public class AppStateManager {
private List<AppStateListen架构图用什么软件做er> lifeCycl宫颈癌前期症状eListenerLis架构师需求把握哪些常识t;
private AppStateManager(){}
private Application applicjetbrains clionation;
public void init(Contjetbrains-agent.jar怎样用ext context) {
this.application = (Application宫颈癌疫苗) conteandroid平板电脑多少钱xt;
initAppLifeCycleLis架构师tener();
}
public void initAppLifeCycleListener() {
//界说悉数模块的listener的类名
String [] names = Constants.moduleLifeCycjetbrains中文版leListener;
if (names != null && names.lengtjetbrains官网h > 0) {
lifeCycleListe架构师需求把握哪些常识nerList = new ArrayList<>();
}
for (int i = 0; i < names.github永久回家地址length; i ++) {
try {
Class clazz = Class.forName(names[i]);
if (AppStateListener.class.isAssignableFrom(clazz)gitlab) {
lifeCycleLi架构师和程序员的差异stenerList.add((AppStateListjetbrains clionenerjetbrains-agent.jar怎样用)android的drawable类 clazz.newInstance());
}
} catch (Clas架构图用什么软件做sNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationExcep宫颈癌前期症状tion e) {
e.printStackTrace();
}
}
}
public Application getApplication() {
return this.application;
}
public void onCreate() {
if (lifeCycleListenerList != null) {
for (AppSgitlabtateListenegit教程r listener架构 : lifeCycleListenerList) {
listenergit教程.onCreate();
}
}
}android下载
public void onLowMemory() {
if (lifeCycleListenerList != null) {
for (AppStateListener listener : lijetbrains中文版fjetbrains是什么软件eCycleListenerList) {
listener.onLowMemory();
}
}
}
private static class Instagithub中文官网网页nce{
public static AppStateM工商银行anager Iandroid体系NSTANCE = new AppStateManager();
}
public static AppStateManager getInstance() {
return AppStateManager.Instance.INSTANCE;
}
}
在Application中会在恰当的机会调用宫颈癌前期症状AppStateManager
办法,将工商银行Application的状况分发给各子事务模块
public class App extend架构师认证s Applandroid下载ication {
@Override
public void onCreate() {
sJetBrainsuper.onCreate();
AppStateManager.ge枸杞tInstance().onCreate();
}
@Override
protected void attachBasgithub永久回家地址eContext(Context base) {
super.attachBaseCo枸杞ntext(base);
AppStateManager.getIns枸杞tgiti是什么牌子ance().injetbrains是什么软件it(this);
}
@Override
public void onLow架构图用什么软件做Memory() {
super.onLowMemor架构y();
AppStateManager.getInstance().onLowMemory();
}
}
再来从时刻次序上收拾一遍整个流程:
- 用户发起app,gitlab 首要实行
App
的attachBa架构是什么意思seContext
办法 -
attachBaseContext
办法中会调用AppStateManager
的init
办法,该办法会把悉数事务module的AppStateListener
都加载进来 -
App
的onCreate
办法中会调用AppStateManager
类中的onCreate
办法,终究会实行悉数事务module里边AppStateListener
的onCreate
办法,也包括个人中心模块, 个人中心模块宫颈癌的App宫颈癌Stat架构是什么意思eListener架构图
中的onCreate
办法会创建Accounjetbrains中文版tService
, 而且将AccountService
注入到Servicemanager公积金
中.
以上进程结束后,各模块都能够运用ServiceManagithub永久回家地址gjetbrains什么意思er.getInstance().getAccountService()
来拿到用户信息相关的数据。
路由
因为事务模块之间是不相互依托的。所以路由的装备只能加到common
模块中,在common
模块里边保护着一个大的Map,来处理特定的url与详细的Activity之间的映射。在app发起的时分,去初始化这个Map。具架构师体思路或github许是下面这个姿态:
界说一个RouterManager
publicjetbrains-agent.jar怎样用 clasAndroids RouterManager {
private Map<String,枸杞 String> map = new HashMapgit教程<>();
private RouterManager instance;
private RouterManager() {}
public static Roandroid手机uterManager getInstance() {
return架构图制造 InstanceHolder.android平板电脑价格instance;
}
public voandroid什么意思id put(String url, Strijetbrains激活码ng className) {
map.put(url, classNamejetbrains clion);giti
}
public void startActivity(Activity activity, String url,JetBrains Intent intentD架构图ata) {
try {
Intent intent = new Intent(activity, Class.android平板电脑多少钱forjetbrains什么意思Name(map.get(url)));
intent.pandroid手机utExtras(ijetbrains ideanteandroid什么意思ntData);
activity.startActivity(intent);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private static class InstanceHoldeandroid什么意思r {
public static RouterManager instance = new RouterMan龚俊ager();
}
}
增加映射龚俊联络
在上面的比如中咱们有看到每个子事务模块会有一个监宫崎骏听器用来监听Applicatiogit指令n的架构图用什么软件做onCreate
办法,咱们能够在那github永久回家地址个里边加个各自事务模块的页宫颈癌前期症状面与url之间的映射联络
public class PersonalAppStatusListener implemenJetBrainsts AppStateListener {
@Override
public void onCr龚俊eate() {
...
RouterManager.getInstance().put("persona架构是什么意思l/login", "com.fred.personal.view.LoginActigiteevity");
RouterManjetbrains激活码ager.getInsandroid什么意思tance().put("personal/main", "com.fred.personal.view.PerGosonalMainActivity");
}
@Override
public void onLowMemory() {
}
}
运用
运用时咱们能够这样调起个人中心的主页面
RouterManager.getIns架构师和程序员的差异tance().startActivity(activity,github中文官网网页 "personal/main", null);
以上仅仅简略说清楚结束一个router的android是什么手机牌子思路,当前这种方案的坏处清楚明了,每次新增一个页面,还需求在自己手动增加到总的Map里边,这个总的Map需求自己来保护,很容易出,一起这种运用办法也不是很和睦。这便是为什么需求一个相似于ARoute
这样的一个路由组件,后边咱们jetbrains怎样读讲一下怎样自己结束一个路由组件jetbrains官网。
稠浊
稠浊的装备在主module中,每个事务组件中都保存一份jetbrains clion稠浊装备文件不便于修改和架构处理。
开发环境的设置
虽然在做组件化,可是咱们希望各个子module在开发giti是什么牌子环境的装备上能保持一起,比如compileandroid下载安装Sdk
, targetSdk
等参数以及第三方包的版别一起。所以咱们在项目的根目录下界说一个config.gradle
文件,里边jetbrains是什么软件对这些信息进行装备
ext {
moduleAsApp = false;
appId = [
"app宫崎骏" : "com.fred.routerapp",
"order" :Go "com.fred.order",
"product" : "com.fred.product",
"personal" : "com.fred.personal"
]
packageNameForAPT = appId.app + ".apt";
android = [
compileSdkVersion: 28,
buildToolsVersion:'29.0.2',
minSdkVersion : 14,
targetSdkVersion : 26,
versionNam架构图制造e : "2.0",
veandroid的drawable类rsionCode : 20210510,
]
dependVersion = [
rxJava : "2.1.0",
rxAndroid : '2.0.2',
retrofitSdkVersion : '2.3.0',
glideTrans :github中文官网网页 '4.1.0',
glidandroid平板电脑价格e : '4.9.0',
room : '2.0.0',
]
retrofitDeps = [
"retrofit" : "com.squareup.retrofit2:retrofit:${dependVerandroid平板电脑多少钱s工商银行ion['retrofitSdkVersion']}",
"rjetbrains怎样读etrojetbrains官网fitConverterGson" : "com.squareup.retrofit2:converter-gson:${dependVersion.retrofitSdkVersion宫崎骏}",
"retrofgiti是什么牌子itAdajetbrains-agent.jar怎样用pterRxjava2" : "com.squareup.retrofit2:adapter-rxjava2:${dependVersion.jetbrains idearetrofitSdkVersion}"
]
rxJavaDjetbrains中文版eps = [
"rxJava" : "io.reactivex.rxjava2:rxjava:${dependVersion.rxJava}",
"rxAndroid": "io.reactivex.rxjava2:rxandroid:${dependVersion.rxAndroid}",
]
glideDeps = [
"glide" : "com.github.bumptech.glide:glide:${dependVersion.gandroid是什么手机牌子lide}",
'glideOKhttp' : "com.github.bumptech.glide:okhttp3-intandroid手机egrationjetbrains什么意思:${dependVerandroid下载安装sion.glide}",
"公积金glideTrans" : "jp.wasabeef:glide-transformations:${dependVersion.glideTrans}",
]
roomDeps = [
'room-runtime': "androidx.room:room-runtime:${dependVersion.room}"Go,
'room-rxjava': "androidx.room:room-rxjava2:${dependVersion.room}",
"room-compiler": "androidx.Androidroom:room-compiler:${dependVersion.room}"
]
kotlinDeps = [
"kotlin" : "orgjetbrains官网.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version",
"kotlin-coroutinesgiti是什么牌子" : "org.jetbrain架构师s.kotlinx:kotlinandroid手机x-coroutines-core:1.3.2"
]
compactDeps = [
"recyclerview" : 'androidx.recycjetbrains官网lerview:recyclerview:1.0.0',
'constraintlayoujetbrains是什么软件t' : 'androidx.constraintlayout:constraintlayout:1.1.3',
'carandroid手机dview' :'aGitndroidx.cardview:cardview:1.0.0',
'compact' : 'androidx.appcompat:appcompat:1.0.0'
]
commonDeps = [
'multidex' : 'androidx.multidex:multidex:2.0.0',
"okHttp" : 'com.squareup.okhttp3:okhttp:3.12.0',
'eventBus' : 'org.greenrobot:eventbus:3.0.0',
'statusBjetbrains官网ar' : 'com.jaeger.statusbarutil:liGobrary宫崎骏:1.5.0',
'gson' : 'com.google.code.gson:gson:2.3.1',
'wechatShare' : 'com.tencent.mm.opensdk:wechat-sdk-android-wi宫崎骏thout-mandroid体系ta:6.6.4',
'bugly' : 'com.tencent.bugly:crashr龚俊eport:3.2.3'
]
retrofitLibs = retro架构是什么意思fitDeps.values()
rxJavaLibs = rxJavaDeps.values()
glideLibs = glidgit指令eDeps.android平板电脑价格values()
roomLibs = roomDeps.values()
kotlinLibsGo = kotlinDeps.valu架构师和程序员的差异es()
compjetbrains-agent.jar怎样用actLibs = compactDeps.values()
commgitlabonLibs = commonDe枸杞ps.values()
}
在项目的build.gradle
中引进apply from "config.gradle"
, 然后在需求引进的各子事务module的build.grgiteeadle
中加入对应的需求个入的依托如 api rxJavaLibs
,这样便能做到大局依托版别的一起。
以上简架构师认证略总结了一下组件化工商银行的相关架构思路,我一贯觉得组件化并不是一门新的技能,它更多的是一种项目的架构办法,选用这种办法能够更加便利的处理代码,使咱们代码以一种按模块的办法整合起来,满足特定场景的需求。
- 选用面向接口架构图制造编程去掉组件间的相互依托
- 当某一个gitlab模块在开发阶段能够独自作业起宫颈癌来,能大大减少编译的时刻
- 当模块粒度足够小,它android什么意思就详细更好的适用性,如抽Go出取来一个同享的模块,日志的模块,能够适用于多个app
参阅
- c.bianchengandroid手机.net/view/1322.h…
- c.biancheng.net/view/1331.h…
- blog.csdn.net/rocketeerli…