Behavior.State状态模式:不同状态平行不可替换,有规律地相互切换

状态模式允许对象在内部状态改变时改变其行为,看起来就像修改了类一样。它将状态和行为封装在独立的类中,通过维护状态的变化来调用不同行为。状态模式中的行为具有平行性,不可互相替换,而策略模式的行为是平等的,可替换。在状态模式中,上下文不处理状态相关行为,而是委托给状态处理类。虽然状态模式可能在添加新实现类时违反OCP原则,但在实际开发中,它提供了灵活应对状态变化的方法。在处理状态对象时,可以按需创建和销毁,或者采用缓存策略。
状态模式(State Pattern)的定义

(1)定义:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

  ①状态和行为,它们的关系可以描述为状态决定行为

  ②因状态是在运行期被改变,行为也会在运行期根据状态的改变而改变。看起来,同一个对象,在不同的运行时刻,行为是不一样的,就像是类被修改了一样

(2)状态模式的结构和说明

 

  ①Context:环境,也称上下文,通常用来定义客户感兴趣的接口,同时维护一个来具体处理当前状态的实例对象

  ②State:状态接口,用来封装与上下文的一个特定状态所对应的行为。

  ③ConcreteState:具体实现状态处理的类,每个类实现一个跟上下文相关的状态的具体处理。

思考状态模式

(1)状态模式的本质:根据状态来分离和选择行为

(2)状态和行为

  ①状态模式的功能就是把状态和状态对应的行为分离出来,每个状态所对应的功能处理封装在一个独立的类里。通过维护状态的变化,来调用不同状态对应的不同功能。

  ②为了操作不同的状态类,定义一个状态接口来约束它们,这样外部就可以面向这个统一的状态接口编程,而无须关心具体的状态类实现了。

  ③状态和行为是相关联的,它们的关系可以描述为状态决定行为。因状态是在运行期被改变,行为也会在运行期根据状态的改变而改变,看起来,同一个对象,在不同的运行时刻,行为是不一样的,就像是类被修改了一样。

(3)行为的平行性

  ①注意是平行性,而不是平等性。所谓的平行性指的是各个状态的行为所处的层次是一样的,相互独立的、没有关联的,是根据不同的状态来决定到底走平行线的哪一条。因为行为是不同的,当然对应的实现也是不同的,相互之间是不可替换的

 

  ②平等性:强调用的可替换性,大家是同一行为的不同描述或实现,因此在同一个行为发生的时候,可以根据条件挑选任意一个实现来进行相应的处理。

 

  ③状态模式的结构和策略模式的结构完全一样。但是它们的目的、实现、本质却完全不同。还有行为之间的特性也是状态模式和策略模式的一个很重要的区别,状态模式的行为是平行性,不可相互替换的;而策略模式的行为是平等的,是可以相互替换的

(4)Context和state

  ①在状态模式中,上下文持有state对象,但上下文本身并不处理跟状态相关的行为,而是把处理状态的功能委托给了状态对应的状态处理类来处理

  ②在具体的状态处理类经常需要获取上下文自身的数据,甚至在必要的时候回调上下文中的方法。因此,通常将上下文自身当作一个参数传递给具体的状态处理类

  ③客户端一般只和上下文交互。客户端通常不负责运行期间状态的维护,也不负责决定后续到底使用哪一个具体的状态处理对象,这点与策略模式是不同的

(5)不完美的OCP体验(开闭原则)

  ①修改功能:由于每个状态对应的处理己经封装到对应的状态类中了,要修改己有的某个状态的功能,直接进行修改那个类就可以了,对其他程序没有影响。

  ②添加新的实现类:得修改Context中request方法这不完全遵循OCP原则。这要说明一下,设计原则是大家在设计和开发中尽量去遵守的,但不是一定要遵守,尤其是完全遵守。因为实际开发中,完全遵守那些原则几乎是不可能完成的任务。

(6)创建和销毁状态对象

  ①如果要进入的状态在运行时是不可知的,而且上下文是比较稳定的,不会经常改变状态,而且使用也不频繁的,可以在需要状态对象的时候创建,使用完销毁它们

  ②如果状态改变很频繁,也就是需要频繁的创建状态对象,而且状态对象还存储着大量的数量信息,这种情况可以提前创建它们并且始终不销毁

  ③如果无法确定状态改变是否频繁,而且有些状态对象的数据量大,有些比较小,一切都是未知的,可以采用延迟加载和缓存结合的方式,就是当第一次需要使用状态对象时创建,使用完后并不销毁对象,而是把这个对象缓存起来,等待一下次使用,而且在合适的时候,由缓存框架销毁状态对象。在实际工程开发过程中,这个方案是首选,因为它兼顾了前两种方案的优点,又避免了它们的缺点。

【编程实验】你公司力排万难终于获得某个酒店的系统开发项目,并且最终落到了你的头上。下图是他们系统的主要工作(够简单)。 当你第一眼看到这个系统的时候你就看出来了这是一个状态图,每个框框都代表了房间的状态,箭头表示房间状态的转换。分析如下:房间有三个状态:空闲、已预订、已入住,状态与状态之间可以根据客户的动作来进行转换。定义每个状态的值。


图片1

aaaa

//声明文件

#include<iostream>
#include<iomanip>
using namespace std;



class CAbsState{
public:
	virtual void BookRoom() = 0;//预订房间 
	virtual void UnsubscribeRoom() = 0;//退订房间 
	virtual void CheckInRoom() = 0;//入住
	virtual void CheckOutRoom() = 0;//退房
};

//房间  
class CRoom{
private:
	CAbsState* pFreeState;//空闲状态
	CAbsState* pCheckInState;//入住状态
	CAbsState* pBookedState;//预订状态
	CAbsState* pCurrState;//当前状态
public:
	CRoom();
	~CRoom();
	void BookRoom();
	void UnsubscribeRoom();
	void CheckInRoom();
	void CheckOutRoom();
	void RoomState();
public:
	void SetFreeState(CAbsState* freestate);
	CAbsState* GetFreeState();
	void SetCheckInState(CAbsState* checkinstate);
	CAbsState* GetCheckInState();
	void SetBookedState(CAbsState* bookedstate);
	CAbsState* GetBookedState();
	void SetCurrState(CAbsState* currstate);
	CAbsState* GetCurrState();
};
//空闲状态只能预订和入住
class CFreeState : public CAbsState{
private:
	CRoom* pRoom;
public:
	CFreeState(CRoom* room);
	void BookRoom();
	void CheckInRoom();
	void UnsubscribeRoom();
	void CheckOutRoom();
};
//预定的房间可以退订和入住
class CBookedState : public CAbsState{
private:
	CRoom* pRoom;
public:
	CBookedState(CRoom* room);
	void BookRoom();
	void CheckInRoom();
	void CheckOutRoom();
	void UnsubscribeRoom();
};

// 入住可以退房 
class CCheckInState : public CAbsState{
private:
	CRoom* pRoom;
public:
	CCheckInState(CRoom* room);
	void BookRoom();
	void CheckInRoom();
	void CheckOutRoom();
	void UnsubscribeRoom();
};

//实现文件

void CRoom::BookRoom(){ pCurrState->BookRoom();}//预订房间
void CRoom::UnsubscribeRoom(){pCurrState->UnsubscribeRoom();}//退订房间
void CRoom::CheckInRoom(){pCurrState->CheckInRoom();}//入住
void CRoom::CheckOutRoom(){pCurrState->CheckOutRoom();}//退房
void CRoom::RoomState(){cout << "该房间的状态是:" << typeid(*pCurrState).name() << endl;}
void CRoom::SetFreeState(CAbsState* freestate){pFreeState = freestate;}
CAbsState* CRoom::GetFreeState(){return pFreeState;}
void CRoom::SetCheckInState(CAbsState* checkinstate){pCheckInState = checkinstate;}
CAbsState* CRoom::GetCheckInState(){return pCheckInState;}
void CRoom::SetBookedState(CAbsState* bookedstate){pBookedState = bookedstate;}
CAbsState* CRoom::GetBookedState(){return pBookedState;}
void CRoom::SetCurrState(CAbsState* currstate){pCurrState = currstate;}
CAbsState* CRoom::GetCurrState(){return pCurrState;}


CFreeState::CFreeState(CRoom* room){pRoom = room;}
void CFreeState::BookRoom(){
	cout << "您已经成功预订了..." << endl;
	pRoom->SetCurrState(pRoom->GetBookedState());//状态变成已经预订
}
void CFreeState::CheckInRoom(){
	cout << "您已经成功入住了..." << endl;
	pRoom->SetCurrState(pRoom->GetCheckInState());//状态变成已经入住
}
void CFreeState::UnsubscribeRoom(){/*不需要做操作*/}
void CFreeState::CheckOutRoom(){/*不需要做操作*/}

//预定的房间可以退订和入住

CBookedState::CBookedState(CRoom* room){pRoom = room;}
void CBookedState::BookRoom(){cout << "该房间已近给预定了..." << endl;}
void CBookedState::CheckInRoom(){
	cout << "入住成功" << endl;
	pRoom->SetCurrState(pRoom->GetCheckInState());
}
void CBookedState::CheckOutRoom(){/*不需要做操作*/}
void CBookedState::UnsubscribeRoom(){
	cout << "退订成功,欢迎下次光临" << endl;
	pRoom->SetCurrState(pRoom->GetFreeState());//变成空闲状态
}

// 入住可以退房 
CCheckInState::CCheckInState(CRoom* room){pRoom = room;}
void CCheckInState::BookRoom(){
	cout << "该房间已经入住了..." << endl;
}
void CCheckInState::CheckInRoom(){
	cout << "该房间已经入住了..." << endl;
}
void CCheckInState::CheckOutRoom(){
	cout << "退房成功..." << endl;
	pRoom->SetCurrState(pRoom->GetFreeState());//状态变成空闲
}
void CCheckInState::UnsubscribeRoom(){/*不需要做操作*/}



CRoom::CRoom(){//房间的三个状态 
	pFreeState = new CFreeState(this);
	pCheckInState = new CCheckInState(this);
	pBookedState = new CBookedState(this);
	pCurrState = pFreeState;////初始状态为空闲 
}
CRoom::~CRoom(){
	delete pFreeState;
	delete pCheckInState;
	delete pBookedState;
}

//测试客户端

void main()
{
	CRoom* pRoom1 = new CRoom();
	CRoom* pRoom2 = new CRoom();
	//第一间房 : 预订--->入住---预订
	cout << "第一间房***************************" << endl;
	pRoom1->BookRoom();
	pRoom1->CheckInRoom();
	pRoom1->BookRoom();//Failed
	pRoom1->RoomState();
	cout << "第二间房***************************" << endl;
	pRoom2->CheckInRoom();
	pRoom2->BookRoom();//Failed
	pRoom2->CheckOutRoom();
	pRoom2->BookRoom();
	pRoom2->RoomState();
	delete pRoom1;
	delete pRoom2;
}

你的这段 Kotlin 代码 **本身会直接导致运行失败**,但是否会导致崩溃或运行时错误,**取决于布局文件中是否存在 `binding.bottomSheet` 这个 View**。 --- ## ✅ 正确性分析: ```kotlin class MainActivity : AppCompatActivity() { private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(binding.root) val behavior = BottomSheetBehavior.from(binding.bottomSheet) behavior.peekHeight = 60 // 初始只显示图标部分 behavior.state = BottomSheetBehavior.STATE_COLLAPSED // 可选监听 behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onStateChanged(bottomSheet: View, newState: Int) { // 监听状态变化 } override fun onSlide(bottomSheet: View, slideOffset: Float) { // 滑动回调 } }) } } ``` --- ## 🚨 潜在崩溃风险点: ### ❌ 1. **binding.bottomSheet 为 null 或存在** 如果你在布局文件(如 `activity_main.xml`)中 **没有定义一个 ID 为 `bottomSheet` 的 View**,或者这个 View **是 `CoordinatorLayout` 的直接子 View**,那么调用 `BottomSheetBehavior.from(binding.bottomSheet)` 时会抛出异常: > `java.lang.IllegalArgumentException: The view is not a child of CoordinatorLayout` #### ✅ 正确写法示例(XML): ```xml <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- BottomSheet --> <LinearLayout android:id="@+id/bottomSheet" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@android:color/white" android:elevation="8dp"> <!-- Bottom sheet content --> <TextView android:layout_width="wrap_content" android:layout_height="40dp" android:text="Bottom Sheet Content" /> </LinearLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout> ``` --- ### ❌ 2. 使用了错误的父布局(是 CoordinatorLayout) `BottomSheetBehavior` **必须绑定在 `CoordinatorLayout` 的直接子 View` 上**。如果你的 `bottomSheet` 的父布局是 `CoordinatorLayout`,也会导致异常。 --- ## ✅ 建议的健壮写法(加空检查): 如果你确定 `bottomSheet` 是否存在,可以使用安全调用: ```kotlin val bottomSheet = binding.bottomSheet if (bottomSheet != null) { val behavior = BottomSheetBehavior.from(bottomSheet) behavior.peekHeight = 60 behavior.state = BottomSheetBehavior.STATE_COLLAPSED // 添加监听器... } else { Log.e("MainActivity", "bottomSheet is null, check your layout file.") } ``` --- ## ✅ 依赖要求 确保你已经在 `build.gradle` 中添加了 **Material Design 依赖**,否则 `BottomSheetBehavior` 会找到: ```groovy implementation 'com.google.android.material:material:1.9.0' ``` --- ## ✅ 总结 | 情况 | 是否会崩溃 | |------|-------------| | 布局中没有 `bottomSheet` 这个 ID | ❌ 会崩溃 | | `bottomSheet` 是 `CoordinatorLayout` 的直接子 View | ❌ 会崩溃 | | 没有导入 `material` 依赖 | ❌ 编译失败 | | 正确使用 `CoordinatorLayout` 和 `bottomSheet` | ✅ 会崩溃 | --- ##
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值