设计模式解析与实战之状态模式
来源:互联网 发布:东盟十国旅游的数据 编辑:程序博客网 时间:2024/05/01 23:56
买了大神关爱民与何红辉所著书籍《设计模式解析与实战》,观后有所感、有所悟。
状态模式:根据其状态改变其行为。例如源码中的控件CheckBox,选中状态和未选中状态,呈现的UI是不同的,原理就是根据isChecked状态,选择绘制不同的背景。下面先来看一组UML(第一次画,画得不好贱笑了):
上图是一个关于LOL的简单UML,LOL的英雄都具有QWERDF技能,不同的英雄释放不同的技能,我们需要获取他释放技能的信息。下面开始编码啦啦
LOLHero.java
public abstract class LOLHero { protected int heroId; public int getHeroId() { return heroId; } public void setHeroId(int heroId) { this.heroId = heroId; } public abstract void skillQ(); public abstract void skillW(); public abstract void skillE(); public abstract void skillR(); public abstract void skillD(); public abstract void skillF();}
为了避免累赘代码,这里以英雄寒冰为例HeroHanBin.java
public class HeroHanBin extends LOLHero { @Override public void skillQ() { System.out.println("我要Q死你丫丫,皮卡丘"); } @Override public void skillW() { System.out.println("看我万箭齐发让你屁股开花,O(∩_∩)O~"); } @Override public void skillE() { System.out.println("丛林是遮不住我的视野,光耀大地!"); } @Override public void skillR() { System.out.println("大招来了,小心了.."); } @Override public void skillD() { System.out.println("这世道变了,我还是归隐山林吧,挥一挥衣袖,不带走一片云彩"); } @Override public void skillF() { System.out.println("点燃吧,基情四射了"); }}
SkillStatus.java和他的继承子类代码不多这里就随便贴点:
public abstract class SkillStatus { public abstract String getSkillInformation();}public class SkillStatusQ extends SkillStatus{ @Override public String getSkillInformation() { return "皮卡丘,我要q死你"; }}public class SkillStatusW extends SkillStatus{ @Override public String getSkillInformation() { return "皮卡丘,我要射死你"; }}
下面开始编写我们工具类HeroFactory.java和SkillType枚举类型
public class HeroFactory{ private static HeroFactory instance; public HeroFactory(){ } public static HeroFactory getInstance(){ if(instance==null){ synchronized (HeroFactory.class) { if(instance==null){ instance=new HeroFactory(); } } } return instance; } public <T extends SkillStatus> T getSkillStatusInstance(Class<T> cls){ T t=null; try { t=cls.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return t; } public <T extends LOLHero> T getLOLHeroInstance(Class<T> cls){ T t=null; try { t=cls.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return t; } public void onSkill(Class<? extends LOLHero> classLOLHero,SkillType skillType){ LOLHero mLOLHero=getLOLHeroInstance(classLOLHero); SkillStatus mSkillStatus=null; switch (skillType.getType()) { case SkillType.SKILL_Q: mLOLHero.skillQ(); mSkillStatus=getSkillStatusInstance(SkillStatusQ.class); break; case SkillType.SKILL_W: mLOLHero.skillW(); mSkillStatus=getSkillStatusInstance(SkillStatusW.class); break; //...............此处略................. default: break; } System.out.println(mSkillStatus.getSkillInformation()); } public enum SkillType{ Q(0),W(1),E(2),R(3),D(4),F(5); private int type; private SkillType(int type){ this.type=type; } public int getType(){ return this.type; } public static final int SKILL_Q=0; public static final int SKILL_W=1; public static final int SKILL_E=2; public static final int SKILL_R=3; public static final int SKILL_D=4; public static final int SKILL_F=5; }}
现在我们可以在测试类HeroTest.java里面开撸啦
public class HeroTest { public static void main(String[] args) { HeroFactory.getInstance().onSkill(HeroHanBin.class, SkillType.Q); System.out.println("*******************************************"); HeroFactory.getInstance().onSkill(HeroHanBin.class, SkillType.W); }}/** 撸出QW技能结果: 我要Q死你丫丫,皮卡丘 皮卡丘,我要q死你 ******************************************* 看我万箭齐发让你屁股开花,O(∩_∩)O~ 皮卡丘,我要射死你 **/
以上实例,根据英雄选择的技能类型,选择不同的SkillStatus实现,不同的状态对应不同的行为,通过以上代码你也许会产生错觉,这不就是策略模式么?我写的有点像那种感觉,那么如果我用setChecked(boolean isChecked) 、getChecked()替代getSkillStatusInformation()方法,调用技能是执行setChecked(!getChecked)你是否会有所体会呢,如果你还不能体会,别着急,接着看下面一个更简单的实例,先上图UML
当然用户信息不止一个登陆状态,这里只例举状态模式相关的,在我们登陆了就把登陆后的信息保存下来,注销了就清理缓存,这里通过MyApplication、Login、Logout来帮助我们例举状态模式。
UserStatus.java接口类
public interface UserStatus { public abstract boolean isLogin();}
LoginStatus.java类和LogoutStatus.java类同理,这里就医LoginStatus.java为例:
public class LoginStatus implements UserStatus{ public LoginStatus() { } @Override public boolean isLogin() { return true; }}
下面是一个测试的伪代码类UserTest.java
public class UserTest { public void onClick(int type){ if(type==1){ //注销 onLogout(new OnLogoutListener() { @Override public void onSuccess() { MyApplication.getInstance().setUserStatus(new LogoutStatus()); System.out.println("注销成功"); } @Override public void onFail() { System.out.println("注销失败"); } }); }else if(type==2){ //登录 onLogin("userName", "password",new OnLoginListener() { @Override public void onSuccess() { MyApplication.getInstance().setUserStatus(new LoginStatus()); System.out.println("登录成功"); } @Override public void onFail() { System.out.println("登录失败"); } }); } } private void onLogout(OnLogoutListener listener) { } public void onLogin(String userName,String password,OnLoginListener listener){ } public interface OnLoginListener{ void onFail(); void onSuccess(); } public interface OnLogoutListener{ void onFail(); void onSuccess(); }}
状态模式虽然好用简单,代码扩展性和维护性好,但是会增加很多类出来,具体使用场景根据开发者需求和习惯而定。下面再来看看状态模式在源码中的实践,这里已RadioGroup+RadioButton为例。
public class RadioGroup extends LinearLayout { /** * {@inheritDoc} */ public RadioGroup(Context context) { super(context); setOrientation(VERTICAL); init(); } /** * {@inheritDoc} */ public RadioGroup(Context context, AttributeSet attrs) { super(context, attrs); // retrieve selected radio button as requested by the user in the // XML layout file TypedArray attributes = context.obtainSt.... attributes.recycle(); init(); } private void init() { }}
RadioGrop一般配合RadioButton使用,我们平时看到的onCheckedChanged()方法源自于内部定义的接口OnCheckedChangeListener,对外公开set 方法,该类还提供了setCheckedId()、getCheckedRadioButtonId()、clearCheck()等方法,这里略提一下clearCheck(),传入-1间接调用check(-1)清除选中状态:
public void check(int id) { // don't even bother if (id != -1 && (id == mCheckedId)) { return; } if (mCheckedId != -1) { //如果当前RadioGroup选中了就调用该方法 setCheckedStateForView(mCheckedId, false); } if (id != -1) { setCheckedStateForView(id, true); } setCheckedId(id); } private void setCheckedStateForView(int viewId, boolean checked) { View checkedView = findViewById(viewId); if (checkedView != null && checkedView instanceof RadioButton) { ((RadioButton) checkedView).setChecked(checked); } }
RadioButton继承自CompoundButton实现了接口Checkable
/** * Defines an extension for views that make them checkable. * */public interface Checkable { /** * Change the checked state of the view * * @param checked The new checked state */ void setChecked(boolean checked); /** * @return The current checked state of the view */ boolean isChecked(); /** * Change the checked state of the view to the inverse of its current state * */ void toggle();}
我们来看看CompoundButton类的实现,这才是本次重点,废话这么久终于找到组织了
public abstract class CompoundButton extends Button implements Checkable { public CompoundButton(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CompoundButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.CompoundButton, defStyleAttr, defStyleRes); //..............此处略............... final boolean checked = a.getBoolean( com.android.internal.R.styleable.CompoundButton_checked, false); setChecked(checked); a.recycle(); applyButtonTint(); }}
这里继续跟进setChecked()代码块,发现对mChecked状态重新赋值,并执行刷新了DrawableStatus,具体刷新原理改变flag值: mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY;在setState(getDrawableState())方法里通过mPrivateFlags的位运算重新给StateListAnimator setState从而改变背景图片:
public void setChecked(boolean checked) { if (mChecked != checked) { mChecked = checked; refreshDrawableState(); //............此处略............... } }
再看这段代码的时候还有奇遇,偶然发现了原型模式在源码中的实践,目标定位StateListAnimator (老实说,在没看爱哥书一前,从来不知原型模式为何物,导致以前阅读源码崩溃现象,现在好多了):
@Override public StateListAnimator clone() { try { StateListAnimator clone = (StateListAnimator) super.clone(); clone.mTuples = new ArrayList<Tuple>(mTuples.size()); clone.mLastMatch = null; clone.mRunningAnimator = null; clone.mViewRef = null; clone.mAnimatorListener = null; clone.initAnimatorListener(); final int tupleSize = mTuples.size(); for (int i = 0; i < tupleSize; i++) { final Tuple tuple = mTuples.get(i); final Animator animatorClone = tuple.mAnimator.clone(); animatorClone.removeListener(mAnimatorListener); clone.addState(tuple.mSpecs, animatorClone); } clone.setChangingConfigurations(getChangingConfigurations()); return clone; } catch (CloneNotSupportedException e) { throw new AssertionError("cannot clone state list animator", e); } }
时而学习之,不亦说乎,逗比要去吹牛逼啦,看不懂别问我,我不知道,看懂了也别@我,没啥好说的
- 设计模式解析与实战之状态模式
- 实战设计模式之状态模式
- 设计模式解析与实战之单列模式
- 设计模式解析与实战之Builder模式
- 设计模式解析与实战之原型模式
- 设计模式解析与实战之工厂方法模式
- 设计模式解析与实战之策略模式
- Android源码设计模式解析与实战之二单例模式
- 《Android源码设计模式解析与实战》读书笔记(八)——状态模式
- java与设计模式之状态模式
- Android源码设计模式解析与实战
- Android 源码设计模式解析与实战
- Android源码设计模式解析与实战
- 设计模式之策略模式与状态模式的区别
- Java设计模式之策略模式与状态模式
- Android 设计模式实战笔记 状态模式
- Android实战设计模式-----状态模式
- 设计模式之状态模式
- UML类图几种关系的总结
- Maven的安装
- Android NDK 和 OpenCV 整合开发总结
- 什么是手游包压缩技术,主要能解决什么问题
- listvuew测量view高度时空指针问题
- 设计模式解析与实战之状态模式
- android surport
- 后台执行linux脚本
- ibatis插入和更新
- python DB操作
- 短信管理器笔记
- Same Tree
- FCM模糊认知映射
- 如何查看jdk的版本