我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版,欢迎购买。点击进入详情
简介
模板设计模式其实在我们平常的编码过程中基本都会用到,现在我们专门针对这个设计模式总结一下,让大家更清晰地了解这个模式。
模板设计模式(Template Pattern)是一种基于代码复用的设计模式。
形象的描述就是架构师和开发人员之间的合作。架构师构造好实现的流程和轮廓,开发人员则完成具体的实现过程。
父类抽象模板:
- 定义abstract限定符方法交由子类实现;
- 定义非private方法,延迟至之类实现,此方法也可以完成一些通用操作;
子类实现模板: - 实现父类abstract方法;
- 可以重写父类非private方法。
模板模式的静态结构图如下:
代码
Car类:
public abstract class Car {
void startUp() {
System.out.println("启动!");
}
abstract void move();//强制要求实现
void stop() {
System.out.println("熄火!");
}
public final void operation(){//定义成final, 防止被重写
//第一步:启动
startUp();
//第二步:驾驶
move();
//第三步:停止
stop();
}
}
我们定义了一个方法operation,里面有三个方法,其中move方法是我们想让之类实现的。
而且operation类为了不被重写,我们定义成了final类型。
BMW类:
public class BMW extends Car {
@Override
void move() {
System.out.println("BMW烧汽油动起来了");
}
}
Bens类:
public class Benz extends Car {
@Override
void move() {
System.out.println("Benz靠电动起来了");
}
}
运行:
Car bmw = new BMW();
bmw.move();
Car benz = new Benz();
benz.move();
AndroidQuick快速开发框架中有一个QuickActivity类复杂一点,但是也更有代表性:
public abstract class QuickActivity extends RxAppCompatActivity implements EasyPermissions.PermissionWithDialogCallbacks, BaseContract.BaseView {
/**
* log tag
*/
protected static String TAG = "QuickActivity";
/**
* context
*/
protected Context mContext = null;
/**
* screen information
*/
protected int mScreenWidth = 0;
protected int mScreenHeight = 0;
protected float mScreenDensity = 0.0f;
/**
* loading view controller
*/
private VaryViewHelperController mVaryViewHelperController = null;
/**
* overridePendingTransition mode
*/
public enum TransitionMode {
LEFT, RIGHT, TOP, BOTTOM, SCALE, FADE
}
/**
* butterknife 8+ support
*/
private Unbinder mUnbinder;
/**
* databinding
*/
private View mainView;
protected ViewDataBinding binding;
/**
* default toolbar
*/
protected TextView tvTitle;
protected TextView tvRight;
protected Toolbar toolbar;
protected FrameLayout toolbarLayout;
private LinearLayout contentView;
/**
* dialog
*/
protected LoadingDialog loadingDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initCreate();
mContext = this;
// activity manager
QuickAppManager.getInstance().addActivity(this);
// animation
if (toggleOverridePendingTransition()) {
switch (getOverridePendingTransitionMode()) {
case LEFT:
overridePendingTransition(R.anim.left_in, R.anim.left_out);
break;
case RIGHT:
overridePendingTransition(R.anim.right_in, R.anim.right_out);
break;
case TOP:
overridePendingTransition(R.anim.top_in, R.anim.top_out);
break;
case BOTTOM:
overridePendingTransition(R.anim.bottom_in, R.anim.bottom_out);
break;
case SCALE:
overridePendingTransition(R.anim.scale_in, R.anim.scale_out);
break;
case FADE:
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
break;
}
}
// extras
Bundle extras = getIntent().getExtras();
if (null != extras) {
getBundleExtras(extras);
}
// eventbus
EventBus.getDefault().register(this);
// screen info
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
mScreenDensity = displayMetrics.density;
mScreenHeight = displayMetrics.heightPixels;
mScreenWidth = displayMetrics.widthPixels;
int layoutId = getContentViewLayoutID();
if (layoutId != 0) {
try {
// databinding support
binding = DataBindingUtil.setContentView(this, layoutId);
if (binding != null) {
mainView = binding.getRoot();
} else {
setContentView(layoutId);
}
} catch (NoClassDefFoundError e) {
setContentView(layoutId);
}
} else {
throw new IllegalArgumentException("You must return a right contentView layout resource Id");
}
// system status bar immersion
StatusBarUtil.setRootViewFitsSystemWindows(this, true);
StatusBarUtil.setTranslucentStatus(this);
if (!StatusBarUtil.setStatusBarDarkTheme(this, true)) {
StatusBarUtil.setStatusBarColor(this, 0x55000000);
}
// network status
NetStateReceiver.registerNetworkStateReceiver(mContext);
initViewsAndEvents(savedInstanceState);
}
@Override
public void setContentView(int layoutResID) {
// 添加toolbar布局
if (isLoadDefaultTitleBar()) {
initToolBarView();
initContentView();
contentView.addView(toolbarLayout, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
View view = getContentView(layoutResID, contentView);
if (view == null) {
LayoutInflater.from(this).inflate(layoutResID, contentView, true);
super.setContentView(contentView, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
} else {
super.setContentView(view, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
}
} else {
super.setContentView(layoutResID);
}
mUnbinder = ButterKnife.bind(this);
if (null != getLoadingTargetView()) {
mVaryViewHelperController = new VaryViewHelperController(getLoadingTargetView());
}
}
protected abstract void initCreate();
protected abstract void initDestroy();
protected abstract boolean isLoadDefaultTitleBar();
protected View getContentView(int layoutResID, LinearLayout contentView) {
return null;
}
protected void initContentView() {
contentView = new LinearLayout(this);
contentView.setOrientation(LinearLayout.VERTICAL);
}
private void initToolBarView() {
toolbarLayout = new FrameLayout(this);
LayoutInflater.from(this).inflate(R.layout.layout_toolbar, toolbarLayout,
true);
tvTitle = (TextView) toolbarLayout.findViewById(R.id.tv_title);
tvRight = (TextView) toolbarLayout.findViewById(R.id.tv_right);
toolbar = (Toolbar) toolbarLayout.findViewById(R.id.toolbar);
toolbar.setTitle("");
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
initToolBarSet(actionBar);
}
protected void initToolBarSet(ActionBar actionBar) {
actionBar.setDisplayShowTitleEnabled(false);
if (actionBar != null) {
actionBar.setDisplayShowHomeEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayUseLogoEnabled(false);
actionBar.setHomeAsUpIndicator(R.drawable.icon_back);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
}
protected Toolbar getToolbar() {
return toolbar;
}
@Override
public void finish() {
super.finish();
QuickAppManager.getInstance().removeActivity(this);
if (toggleOverridePendingTransition()) {
switch (getOverridePendingTransitionMode()) {
case LEFT:
overridePendingTransition(R.anim.left_in, R.anim.left_out);
break;
case RIGHT:
overridePendingTransition(R.anim.right_in, R.anim.right_out);
break;
case TOP:
overridePendingTransition(R.anim.top_in, R.anim.top_out);
break;
case BOTTOM:
overridePendingTransition(R.anim.bottom_in, R.anim.bottom_out);
break;
case SCALE:
overridePendingTransition(R.anim.scale_in, R.anim.scale_out);
break;
case FADE:
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
break;
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
initDestroy();
if (mUnbinder != null) {
mUnbinder.unbind();
}
NetStateReceiver.unRegisterNetworkStateReceiver(mContext);
EventBus.getDefault().unregister(this);
dismissLoadingDialog();
}
/**
* get bundle data
*
* @param extras
*/
protected abstract void getBundleExtras(Bundle extras);
/**
* bind layout resource file
*
* @return id of layout resource
*/
protected abstract int getContentViewLayoutID();
/**
* when event coming
*
* @param eventCenter
*/
protected abstract void onEventComing(EventCenter eventCenter);
/**
* get loading target view
*/
protected abstract View getLoadingTargetView();
/**
* init all views and add events
*/
protected abstract void initViewsAndEvents(Bundle savedInstanceState);
/**
* toggle overridePendingTransition
*
* @return
*/
protected abstract boolean toggleOverridePendingTransition();
/**
* get the overridePendingTransition mode
*/
protected abstract TransitionMode getOverridePendingTransitionMode();
/**
* apply systembar color tint
*/
protected abstract boolean isApplySystemBarTint();
/**
* 会被子类覆盖去封装 跳转到不同的activity 或者fragment的页面
*
* @param clazz
* @return
*/
protected Intent getGoIntent(Class<?> clazz) {
return new Intent(this, clazz);
}
/**
* startActivity
*
* @param clazz
*/
protected void readyGo(Class<?> clazz) {
Intent intent = getGoIntent(clazz);
startActivity(intent);
}
/**
* startActivity with flag
* @param clazz
* @param flag
*/
protected void readyGo(Class<?> clazz, int flag) {
Intent intent = getGoIntent(clazz);
intent.setFlags(flag);
startActivity(intent);
}
/**
* startActivity with bundle
*
* @param clazz
* @param bundle
*/
protected void readyGo(Class<?> clazz, Bundle bundle) {
Intent intent = getGoIntent(clazz);
if (null != bundle) {
intent.putExtras(bundle);
}
startActivity(intent);
}
/**
* startActivity with bundle and flag
* @param clazz
* @param bundle
* @param flag
*/
protected void readyGo(Class<?> clazz, Bundle bundle, int flag) {
Intent intent = getGoIntent(clazz);
if (null != bundle) {
intent.putExtras(bundle);
}
intent.setFlags(flag);
startActivity(intent);
}
/**
* startActivity then finish
*
* @param clazz
*/
protected void readyGoThenKill(Class<?> clazz) {
Intent intent = getGoIntent(clazz);
startActivity(intent);
finish();
}
/**
* startActivity with bundle then finish
*
* @param clazz
* @param bundle
*/
protected void readyGoThenKill(Class<?> clazz, Bundle bundle) {
Intent intent = getGoIntent(clazz);
if (null != bundle) {
intent.putExtras(bundle);
}
startActivity(intent);
finish();
}
/**
* startActivityForResult
*
* @param clazz
* @param requestCode
*/
protected void readyGoForResult(Class<?> clazz, int requestCode) {
Intent intent = getGoIntent(clazz);
startActivityForResult(intent, requestCode);
}
/**
* startActivityForResult with bundle
*
* @param clazz
* @param requestCode
* @param bundle
*/
protected void readyGoForResult(Class<?> clazz, int requestCode, Bundle bundle) {
Intent intent = new Intent(this, clazz);
if (null != bundle) {
intent.putExtras(bundle);
}
startActivityForResult(intent, requestCode);
}
/**
* show toast
*
* @param msg
*/
protected void showToast(String msg) {
//防止遮盖虚拟按键
if (null != msg && !StringUtil.isEmpty(msg)) {
Snackbar.make(getLoadingTargetView(), msg, Snackbar.LENGTH_SHORT).show();
}
}
/**
* toggle show loading
*
* @param toggle
*/
protected void toggleShowLoading(boolean toggle, String msg) {
if (null == mVaryViewHelperController) {
throw new IllegalArgumentException("You must return a right target view for loading");
}
if (toggle) {
mVaryViewHelperController.showLoading(msg);
} else {
mVaryViewHelperController.restore();
}
}
/**
* toggle show empty
*
* @param toggle
*/
protected void toggleShowEmpty(boolean toggle, String msg, View.OnClickListener onClickListener) {
if (null == mVaryViewHelperController) {
throw new IllegalArgumentException("You must return a right target view for loading");
}
if (toggle) {
mVaryViewHelperController.showEmpty(msg, onClickListener);
} else {
mVaryViewHelperController.restore();
}
}
/**
* toggle show error
*
* @param toggle
*/
protected void toggleShowError(boolean toggle, String msg, View.OnClickListener onClickListener) {
if (null == mVaryViewHelperController) {
throw new IllegalArgumentException("You must return a right target view for loading");
}
if (toggle) {
mVaryViewHelperController.showError(msg, onClickListener);
} else {
mVaryViewHelperController.restore();
}
}
/**
* toggle show network error
*
* @param toggle
*/
protected void toggleNetworkError(boolean toggle, View.OnClickListener onClickListener) {
if (null == mVaryViewHelperController) {
throw new IllegalArgumentException("You must return a right target view for loading");
}
if (toggle) {
mVaryViewHelperController.showNetworkError(onClickListener);
} else {
mVaryViewHelperController.restore();
}
}
protected void toggleRestore() {
if (null == mVaryViewHelperController) {
throw new IllegalArgumentException("You must return a right target view for loading");
}
mVaryViewHelperController.restore();
}
@Subscribe(threadMode = ThreadMode.MainThread)
public void onEventBus(EventCenter eventCenter) {
if (null != eventCenter) {
onEventComing(eventCenter);
}
}
/**
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* Android6.0权限控制
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/
private Map<Integer, PermissionCallback> mPermissonCallbacks = null;
private Map<Integer, String[]> mPermissions = null;
public interface PermissionCallback {
/**
* has all permission
*
* @param allPerms all permissions
*/
void hasPermission(List<String> allPerms);
/**
* denied some permission
*
* @param deniedPerms denied permission
* @param grantedPerms granted permission
* @param hasPermanentlyDenied has permission denied permanently
*/
void noPermission(List<String> deniedPerms, List<String> grantedPerms, Boolean hasPermanentlyDenied);
/**
* @param dialogType dialogType
* @param callback callback from easypermissions
*/
void showDialog(int dialogType, EasyPermissions.DialogCallback callback);
}
/**
* request permission
*
* @param dialogType dialogType
* @param requestCode requestCode
* @param perms permissions
* @param callback callback
*/
public void performCodeWithPermission(int dialogType,
final int requestCode, @NonNull String[] perms, @NonNull PermissionCallback callback) {
if (EasyPermissions.hasPermissions(this, perms)) {
callback.hasPermission(Arrays.asList(perms));
} else {
if (mPermissonCallbacks == null) {
mPermissonCallbacks = new HashMap<>();
}
mPermissonCallbacks.put(requestCode, callback);
if (mPermissions == null) {
mPermissions = new HashMap<>();
}
mPermissions.put(requestCode, perms);
EasyPermissions.requestPermissions(this, dialogType, requestCode, perms);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
@Override
public void onPermissionsGranted(int requestCode, List<String> perms) {
if (mPermissonCallbacks == null || !mPermissonCallbacks.containsKey(requestCode)) {
return;
}
if (mPermissions == null || !mPermissions.containsKey(requestCode)) {
return;
}
// 100% granted permissions
if (mPermissions.get(requestCode).length == perms.size()) {
mPermissonCallbacks.get(requestCode).hasPermission(Arrays.asList(mPermissions.get(requestCode)));
}
}
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
if (mPermissonCallbacks == null || !mPermissonCallbacks.containsKey(requestCode)) {
return;
}
if (mPermissions == null || !mPermissions.containsKey(requestCode)) {
return;
}
//granted permission
List<String> grantedPerms = new ArrayList<>();
for (String perm : mPermissions.get(requestCode)) {
if (!perms.contains(perm)) {
grantedPerms.add(perm);
}
}
//check has permission denied permanently
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
mPermissonCallbacks.get(requestCode).noPermission(perms, grantedPerms, true);
} else {
mPermissonCallbacks.get(requestCode).noPermission(perms, grantedPerms, false);
}
}
@Override
public void onDialog(int requestCode, int dialogType, EasyPermissions.DialogCallback callback) {
if (mPermissonCallbacks == null || !mPermissonCallbacks.containsKey(requestCode)) {
return;
}
mPermissonCallbacks.get(requestCode).showDialog(dialogType, callback);
}
public void showLoadingDialog() {
showLoadingDialog(null);
}
public void showLoadingDialog(String tips) {
if (!isFinishing()) {
try {
if (loadingDialog == null) {
loadingDialog = new LoadingDialog(this);
if (!StringUtil.isEmpty(tips)) {
loadingDialog.setTip(tips);
}
loadingDialog.show();
} else {
//相同的上下文,无需重新创建
if (loadingDialog.getLoadingDialogContext() == this) {
loadingDialog.show();
} else {
loadingDialog.dismiss();
loadingDialog = new LoadingDialog(this);
if (!StringUtil.isEmpty(tips)) {
loadingDialog.setTip(tips);
}
loadingDialog.show();
}
}
} catch (Throwable e) {
}
}
}
public void dismissLoadingDialog() {
try {
if (!isFinishing() && loadingDialog != null && loadingDialog.isShowing()) {
loadingDialog.dismiss();
}
} catch (Throwable e) {
}
}
public CommonDialog.Builder getDialogBuilder(Context context) {
return new CommonDialog.Builder(context);
}
@Override
public void showLoading() {
}
@Override
public void showSuccess() {
}
@Override
public void showFail() {
}
@Override
public void showRetry() {
}
@Override
public void showMessage(String message) {
}
@Override
public <T> LifecycleTransformer<T> bindToLife() {
return this.<T>bindToLifecycle();
}
}