哪些常見的場景適合使用
策略模式
呢刻剥?我在寫聊天界面的時候遇到了一個非常適合用策略模式
的地方囚聚,與大家分享 (本文以Android的聊天界面為案例厉斟,ios也是一個道理)
本文不做介紹策略模式
到底是什么兼犯,網(wǎng)上別人寫的很詳細珍语。
聊天界面的ViewHolder (ios中叫Cell)一共有哪幾種類型锤岸?
ViewHolder | 位置 | 內(nèi)容 | 上傳狀態(tài)View |
---|---|---|---|
MySend_Text_ViewHolder | 左 | 發(fā)文字 | 有 |
MyReceived_Text_ViewHolder | 右 | 收文字 | 沒有 |
MySend_Image_ViewHolder | 左 | 發(fā)圖片 | 有 |
MyReceived_Image_ViewHolder | 右 | 收圖片 | 沒有 |
MySend_Voice_ViewHolder | 左 | 發(fā)語音條 | 有 |
MyReceived_Voice_ViewHolder | 右 | 收語音條 | 沒有 |
MySend_Location_ViewHolder | 左 | 發(fā)位置 | 有 |
MyReceived_Location_ViewHolder | 右 | 收位置 | 沒有 |
MySend_Call_ViewHolder | 左 | 發(fā)語音通話 | 有 |
MyReceived_Call_ViewHolder | 右 | 收語音通話 | 沒有 |
老方案1:左邊是BaseTextHolder,右邊的MySend_Text_ViewHolder extend BaseTextHolder板乙,然后加上progressbar 和 statusIV
缺點:
- private progressbar 和 private statusIV要寫5次(寫在MySend_XXX_ViewHolder類)
- 右邊要為了上傳的進度控件要復(fù)制粘貼多次findSubmitStatusViewById 和 diaplaySubmitStatusView
- 拓展性差是偷,如果在別的場景假如有多種位置的Item,要多寫很多類代碼
老方案2:左右都用TextHolder募逞;TextHolder包含private progressbar 和 private statusIV蛋铆;然后TextHolder有個isRight 的 boolean字段
缺點:
- private progressbar 和 private statusIV要寫5次(在TextHolder類里寫)
- 右邊要為了上傳的進度控件要復(fù)制粘貼多次findSubmitStatusViewById 和 diaplaySubmitStatusView
一切的原因,都是java 和 oc不支持多繼承放接,要是有多繼承刺啦,可以讓MySend_Text_ViewHolder extend BaseTextHolder,SubmitStatusHolder多好
下面使用策略模式,很好的解決了這些問題纠脾,代碼實現(xiàn)完美封裝(以下只拿Text文本消息來舉例)
//聊天Item的位置Interface(如果是我發(fā)出的玛瘸,就在右邊;我收到的消息苟蹈,在左邊)
public interface IBubbleDirection {
//在getView()方法里的 convertView == null里觸發(fā)個方法
public void findChildView(View convertView);
//在getView()方法里 顯示上傳View的值
public void display(int submitStatus);
}
public class RightBubbleDirectionImpl implements IBubbleDirection {
private ProgressBar submitProgressBar;//上傳中的進度條
private ImageView submitStatusImageView;//上傳失敗的感嘆號
@Override
public void findChildView(View convertView) {
submitProgressBar = (ProgressBar) convertView.findViewById(R.id.progress_bar);
submitStatusImageView = (ImageView) convertView.findViewById(R.id.msg_status_iv);
}
@Override
public void display(int submitStatus) {
switch (submitStatus) {
case ChatBean.SUCCESS: // 發(fā)送成功
submitProgressBar.setVisibility(View.GONE);
submitStatusImageView.setVisibility(View.GONE);
break;
case ChatBean.FAIL: // 發(fā)送失敗
submitProgressBar.setVisibility(View.GONE);
submitStatusImageView.setVisibility(View.VISIBLE);
break;
case ChatBean.INPROGRESS: // 發(fā)送中
submitProgressBar.setVisibility(View.VISIBLE);
submitStatusImageView.setVisibility(View.GONE);
break;
}
}
}
public class ChatListAdapter extends BaseAdapter {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
case MESSAGE_TYPE_RECV_TXT://我接受的文本消息
case MESSAGE_TYPE_SENT_TXT:{//我發(fā)出的文本消息
TextViewHolder holder;
if (convertView == null) {
holder = new TextViewHolder(
type == MESSAGE_TYPE_SENT_TXT ? new RightBubbleDirectionImpl() : new LeftBubbleDirectionImpl(),
new TextBubbleViewImpl(myUserPhoto, onChatActionListener, mOnLinkClickListener));
convertView = mInflater.inflate(type == MESSAGE_TYPE_SENT_TXT ? R.layout.chatitem_sent_message : R.layout.chatitem_received_message, null);
//讓holder去findViewById
holder.findChildView(convertView);
convertView.setTag(holder);
} else {
holder = (TextViewHolder) convertView.getTag();
}
holder.display(position, bean);
}
break;
}
//接受-文本-Text ; 其實這里無需 extends BaseTextViewHolder
public static class TextViewHolder extends BaseTextViewHolder{
private IBubbleDirection bubbleDirection;//上傳progress和statusiv控件
private IBubbleView bubbleView;//文本Item控件
public TextViewHolder(IBubbleDirection bubbleDirection, IBubbleView bubbleView){
this.bubbleDirection = bubbleDirection;
this.bubbleView = bubbleView;
}
public void findChildView(View convertView){
//初始化Item自己的view
bubbleView.findChildView(convertView);
//初始化上傳狀態(tài)View
bubbleDirection.findChildView(convertView);
}
public void display(int position, ChatBean chatBean){
//處理Item自己的view
bubbleView.display(position, chatBean);
//處理上傳狀態(tài)View
displaySubmitView(chatBean.getState());
}
//因為外部ac可能要重置上傳狀態(tài)捧韵,所以這里設(shè)置為public
public void displaySubmitView(int submitStatus){
//處理上傳狀態(tài)View
bubbleDirection.display(submitStatus);
}
}
總結(jié):在什么情況下適合使用 橋接模式
- 你希望雙繼承的時候:比如聊天的ViewHolder,“我發(fā)出的圖片消息” 既想extend BaseImageViewHolder汉操,又想 extend BaseUploadViewHolder
- 你想創(chuàng)建N個對象再来,這N個對象有若干個共同的特點(或者說方法) :比如
文字消息ViewHolder
,無論左右,他的View的都是普通文字(這是 文字消息的共同特點)芒篷;同時我發(fā)出的消息ViewHolder
又有個共同特點:都有progress 和 statusImageView
以上搜变,我們就可以把其中一組特點
(比如 發(fā)出的消息),抽成一個接口针炉,然后用RightViewHolderImpl實現(xiàn)這個接口挠他;然后安心搞好 TextViewHolder、ImageViewHolder就好了 - 關(guān)于
橋接模式
和策略模式
的區(qū)別:
下面是橋接模式:
//橋接模式:注意這里篡帕,IBubbleDirection是由父類控制的
public abstract class FatherTextViewHolder {
private IBubbleDirection bubbleDirectionInterFace
public FatherTextViewHolder(IBubbleDirection bubbleDirectionInterFace) {
this.bubbleDirectionInterFace = bubbleDirectionInterFace
}
public void fatherDisplay(){
bubbleDirectionInterFace.display()
}
}
//橋接模式中殖侵,子類無需關(guān)心接口的實現(xiàn)方式,由父類實現(xiàn)
class ChildTextViewHolder extend FatherTextViewHolder{
override
public void fatherDisplay(){
super.fatherDisplay()
//TODO 子類自己的代碼
}
}
//橋接模式與策略模式區(qū)別就在于:他多了父類這一步镰烧,在父類中實現(xiàn)接口拢军;而策略模式?jīng)]有父類
class ChildTextViewHolder2 extend FatherTextViewHolder{
override
public void fatherDisplay(){
super.fatherDisplay()
//TODO 子類自己的代碼
}
}
下面是策略模式:
//策略模式要比橋接簡單一下,就單純的一層
public class TextViewHolder {
private IBubbleDirection bubbleDirectionInterFace
public TextViewHolder(IBubbleDirection bubbleDirectionInterFace) {
this.bubbleDirectionInterFace = bubbleDirectionInterFace
}
public void myDisplay(){
bubbleDirectionInterFace.display()
//TODO 自己的代碼
}
}