设计模式之装饰者模式Decorator
装饰者模式,动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案
结构说明
优点
缺点
1、会产生很多的小对象,增加了系统的复杂性
2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐
装饰者的使用场景
1、在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
2、需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。
玩过游戏的兄弟应该都知道,游戏里面每个角色有武器、鞋子、护腕、戒指、还有各种红宝石、蓝宝石、黄宝石等等。
下面需求开始:设计游戏的装备系统,基本要求,要可以计算出每种装备在镶嵌了各种宝石后的攻击力和描述:
/**
* 装备的接口
*/
public interface IEquip
{
//计算攻击力
public int caculateAttack();
//装备的描述
public String description();
}
/**
* 武器
* 攻击力20
*/
public class ArmEquip implements IEquip
{
@Override
public int caculateAttack()
{
return 20;
}
@Override
public String description()
{
return "屠龙刀";
}
}
/**
* 装饰品的接口
*/
public interface IEquipDecorator extends IEquip
{
}
/**
* 蓝宝石装饰品
* 每颗攻击力+5
*/
public class BlueGemDecorator implements IEquipDecorator
{
private IEquip equip;
public BlueGemDecorator(IEquip equip)
{
this.equip = equip;
}
@Override
public int caculateAttack()
{
return 5 + equip.caculateAttack();
}
@Override
public String description()
{
return equip.description() + "+ 蓝宝石";
}
}
/**
* 红宝石装饰品 每颗攻击力+15
*/
public class RedGemDecorator implements IEquipDecorator
{
private IEquip equip;
public RedGemDecorator(IEquip equip)
{
this.equip = equip;
}
@Override
public int caculateAttack()
{
return 15 + equip.caculateAttack();
}
@Override
public String description()
{
return equip.description() + "+ 红宝石";
}
}
// 一个镶嵌1颗红宝石,1颗蓝宝石的武器
System.out.println(" 一个镶嵌1颗红宝石,1颗蓝宝石的武器");
equip = new RedGemDecorator(new BlueGemDecorator(new ArmEquip()));
System.out.println("攻击力 : " + equip.caculateAttack());
System.out.println("描述 :" + equip.description());
/**
* 被装饰者类,适配RecyclerView数据
*/
public class MusicRecyclerAdapter extends BaseAdapter<MusicBean> {
private static final String TAG = "MusicRecyclerAdapter";
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.music_list_item,null);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
view.setLayoutParams(lp);
return new MusicViewHolder(view);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
MusicViewHolder musicViewHolder = (MusicViewHolder)holder;
musicViewHolder.mPosition = position;
MusicBean musicBean = mDataList.get(position);
musicViewHolder.mSongName.setText(musicBean.getSongname());
musicViewHolder.mSinger.setText(musicBean.getSingername());
}
private class MusicViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener{
View mRootView;
TextView mSongName;
TextView mSinger;
int mPosition;
MusicViewHolder(View itemView) {
super(itemView);
mSongName = (TextView)itemView.findViewById(R.id.tv_song_name);
mSinger = (TextView)itemView.findViewById(R.id.tv_singer);
mRootView = itemView.findViewById(R.id.rl_music_item);
mRootView.setOnClickListener(this);
mRootView.setOnLongClickListener(this);
}
@Override
public void onClick(View view) {
if (null != mOnRecyclerViewListener){
mOnRecyclerViewListener.onItemClick(mPosition);
Log.e(TAG, "onClick: "+mPosition);
}
}
@Override
public boolean onLongClick(View view) {
if (null != mOnRecyclerViewListener){
mOnRecyclerViewListener.onItemLongClick(mPosition);
}
return false;
}
}
}
/**
* 装饰者类,用于显示加载更多和已经到底
*/
public class LoadMoreAdapterWrapper extends BaseAdapter<MusicBean> {
private static final String TAG = "LoadMoreAdapterWrapper";
private BaseAdapter mAdapter;
private boolean mHasMoreData = true;
private OnLoadMoreDataRv mMoreDataRecyclerView;
public LoadMoreAdapterWrapper(BaseAdapter baseAdapter, OnLoadMoreDataRv loadMoreDataRecyclerView){
mAdapter = baseAdapter;
mMoreDataRecyclerView = loadMoreDataRecyclerView;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == R.layout.list_item_no_more){
View view = LayoutInflater.from(parent.getContext()).inflate(viewType,parent,false);
return new NoMoreItemVH(view);
}else if (viewType == R.layout.list_item_loading){
View view = LayoutInflater.from(parent.getContext()).inflate(viewType,parent,false);
return new LoadingItemVH(view);
}else {
return mAdapter.onCreateViewHolder(parent,viewType);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof LoadingItemVH){
mMoreDataRecyclerView.loadMoreData();
}else if (holder instanceof NoMoreItemVH){
}else {
mAdapter.onBindViewHolder(holder,position);
}
}
@Override
public int getItemCount() {
return mAdapter.getItemCount() + 1;
}
@Override
public int getItemViewType(int position) {
if (position == getItemCount() - 1){
if (mHasMoreData){
return R.layout.list_item_loading;
}else {
return R.layout.list_item_no_more;
}
}else {
return mAdapter.getItemViewType(position);
}
}
private static class NoMoreItemVH extends RecyclerView.ViewHolder{
private NoMoreItemVH(View itemView) {
super(itemView);
}
}
private static class LoadingItemVH extends RecyclerView.ViewHolder{
private LoadingItemVH(View itemView) {
super(itemView);
}
}
/**
* 设置是否还有数据
*/
public void setHasMoreData(boolean hasMoreData){
mHasMoreData = hasMoreData;
}
}
private BaseAdapter mAdapter;
public LoadMoreAdapterWrapper(BaseAdapter baseAdapter, OnLoadMoreDataRv loadMoreDataRecyclerView){
mAdapter = baseAdapter;
mMoreDataRecyclerView = loadMoreDataRecyclerView;
}
@Override
public int getItemViewType(int position) {
if (position == getItemCount() - 1){
if (mHasMoreData){
return R.layout.list_item_loading;
}else {
return R.layout.list_item_no_more;
}
}else {
return mAdapter.getItemViewType(position);
}
}
@Override
public int getItemCount() {
return mAdapter.getItemCount() + 1;
}
//创建被装饰者实例
mRecyclerAdapter = new MusicRecyclerAdapter();
//创建装饰者实例,并传入被装饰者和回调
mLoadMoreAdapterWrapper = new LoadMoreAdapterWrapper(mRecyclerAdapter,this);
mRvMusicList.setAdapter(mLoadMoreAdapterWrapper);
public abstract class Context {
/**
* File creation mode: the default mode, where the created file can only
* be accessed by the calling application (or all applications sharing the
* same user ID).
* @see #MODE_WORLD_READABLE
* @see #MODE_WORLD_WRITEABLE
*/
public static final int MODE_PRIVATE = 0x0000;
/**
* Same as {@link #startActivity(Intent, Bundle)} with no options
* specified.
*
* @param intent The description of the activity to start.
*
* @throws ActivityNotFoundException
*`
* @see #startActivity(Intent, Bundle)
* @see PackageManager#resolveActivity
*/
public abstract void startActivity(Intent intent);
@Nullable
public abstract ComponentName startService(Intent service);
/**
* Disconnect from an application service. You will no longer receive
* calls as the service is restarted, and the service is now allowed to
* stop at any time.
*
* @param conn The connection interface previously supplied to
* bindService(). This parameter must not be null.
*
* @see #bindService
*/
public abstract void unbindService(@NonNull ServiceConnection conn);
...//等等
}
/**
* Common implementation of Context API, which provides the base
* context object for Activity and other application components.
*/
class ContextImpl extends Context {
private final static String TAG = "ApplicationContext";
private final static boolean DEBUG = false;
private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
new HashMap<String, SharedPreferencesImpl>();
。。。。。。
@Override
public void startActivity(Intent intent) {
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity)null, intent, -1);
}
.....
/**
* Proxying implementation of Context that simply delegates all of its calls to
* another Context. Can be subclassed to modify behavior without changing
* the original Context.
*/
public class ContextWrapper extends Context {
Context mBase;
public ContextWrapper(Context base) {
mBase = base;
}
...
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
....
}
public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
.....
private static final String TAG = "Service";
public Service() {
super(null);
}
/** Return the application that owns this service. */
public final Application getApplication() {
return mApplication;
}
/**
* Called by the system when the service is first created. Do not call this method directly.
*/
public void onCreate() {
}
public @StartResult int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) {
onStart(intent, startId);
return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
/**
* Called by the system to notify a Service that it is no longer used and is being removed. The
* service should clean up any resources it holds (threads, registered
* receivers, etc) at this point. Upon return, there will be no more calls
* in to this Service object and it is effectively dead. Do not call this method directly.
*/
public void onDestroy() {
}
.....
// ------------------ Internal API ------------------
/**
* @hide
*/
public final void attach(
Context context,
ActivityThread thread, String className, IBinder token,
Application application, Object activityManager) {
attachBaseContext(context);
mThread = thread; // NOTE: unused - remove?
mClassName = className;
mToken = token;
mApplication = application;
mActivityManager = (IActivityManager)activityManager;
mStartCompatibility = getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.ECLAIR;
}
.....
}
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
@Override
public void startActivity(Intent intent) {
warnIfCallingFromSystemProcess();
startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
// Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
// generally not allowed, except if the caller specifies the task id the activity should
// be launched in.
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
&& options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}
......
设计模式之装饰者模式Decorator相关推荐
- python中的装饰器、装饰器模式_python 设计模式之装饰器模式 Decorator Pattern
#写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...
- python 设计模式之装饰器模式 Decorator Pattern
#写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...
- C#设计模式(9)——装饰者模式(Decorator Pattern)
一.引言 在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类).A ...
- Java设计模式(装饰者模式-组合模式-外观模式-享元模式)
Java设计模式Ⅳ 1.装饰者模式 1.1 装饰者模式概述 1.2 代码理解 2.组合模式 2.1 组合模式概述 2.2 代码理解 3.外观模式 3.1 外观模式概述 3.2 代码理解 4.享元模式 ...
- 设计模式 之 装饰者模式
2019独角兽企业重金招聘Python工程师标准>>> 设计模式 之 装饰者模式 装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对 ...
- 【设计模式】装饰者模式 ( 概念 | 适用场景 | 优缺点 | 与继承对比 | 定义流程 | 运行机制 | 案例分析 )
文章目录 I . 装饰者模式概念 II . 装饰者模式适用场景 III . 装饰者模式优缺点 IV . 装饰者模式与继承对比 V . 装饰者模式相关设计模式 VI . 装饰者模式四个相关类 VII . ...
- 设计模式学习----装饰器模式
这两天本来是自在学习java collection Framework的Fail Fast底层机制,看到核心的部分时,突然意识到设计模式的问题,上大学到现在我还没有真正理解过设计模式的概念,于是用了大 ...
- go设计模式之装饰器模式
go设计模式之装饰器模式 再写这篇文章时,我已经看了很多其他人发表的类似文章,大概看了这么多吧. 亓斌的设计模式-装饰者模式(Go语言描述) jeanphorn的Golang设计模式之装饰模式 七八月 ...
- 5分钟读懂设计模式(2)---装饰者模式
每当我们买了新房子之后,相信绝大部分人都会进行装修,给房子增加一些其他新的物品.不过,无论如何装修,这个房子还是这个房子,最本质的东西并没有变,有的只是我们通过装修的方式,给这个房子增加了一些额外的功 ...
最新文章
- cocos2d-x 3.8.1的骨骼动画加载方法addArmatureFileInfo仍然存在问题
- datatables ajax 数组,datatables ajax row undefined
- 程序员该知道的7个必经阶段
- input的表单验证(不断更新中~~)
- des和aes相比较有哪些特点_栓流气力输送相比较传统的高速气力输送方式而言,有哪些优势?...
- Java编写简单密码问题
- odoo中页面跳转相关
- php搜索文件名,PHP搜索文件且列出文件名的代码参考
- Spark中如何管理Spark Streaming消费Kafka的偏移量
- nexus3.x批量上传jar包
- 计算机房加湿机,数据中心加湿系统计算及方法探讨【新规范加湿方式对比及计算分析】...
- 2021中青杯数学建模B题
- 【博客分享】优秀的有趣的博客
- Matlab求解空间曲线的切线和法平面
- 大数据分析服务器硬件配置如何选择
- Python: sys.path.append()用法
- 苹果微信换行怎么打_苹果手机微信怎么加密,教你几招快速加密
- 安卓车机root改流浪地球_你想知道的《流浪地球》的问题,都在这里了
- ZYNQ PS端模块读书笔记-中断
- ZYNQ-7的芯片引脚