C#语言是一种强类型语言,在程序中用到的变量、表达式和数值等都必须有类型,编译器检查所有数据类型操作的合法性,非法数据类型操作不会被编译。c#中,两种不同性质的数据类型,分别是值类型和引用类型。
如果在一个系统中对象之间的联系呈现为网状结构,如图20-4所示。对象之间存在大量的多对多联系,将导致系统非常复杂,这些对象既会影响别的对象,也会被别的对象所影响,这些对象称为同事对象,它们之间通过彼此的相互作用实现系统的行为。在网状结构中,几乎每个对象都需要与其他对象发生相互作用,而这种相互作用表现为一个对象与另外一个对象的直接耦合,这将导致一个过度耦合的系统。
图20-4 对象之间存在复杂关系的网状结构
中介者模式可以使对象之间的关系数量急剧减少,通过引入中介者对象,可以将系统的网状结构变成以中介者为中心的星形结构,如图20-5所示。在这个星形结构中,同事对象不再直接与另一个对象联系,它通过中介者对象与另一个对象发生相互作用。中介者对象的存在保证了对象结构上的稳定,也就是说,系统的结构不会因为新对象的引入带来大量的修改工作。
图20-5 引入中介者对象的星型结构
如果在一个系统中对象之间存在多对多的相互关系,我们可以将对象之间的一些交互行为从各个对象中分离出来,并集中封装在一个中介者对象中,并由该中介者进行统一协调,这样对象之间多对多的复杂关系就转化为相对简单的一对多关系。通过引入中介者来简化对象之间的复杂交互,中介者模式是“迪米特法则”的一个典型应用。
中介者模式定义如下:
中介者模式(Mediator Pattern):用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。
在中介者模式中,我们引入了用于协调其他对象/类之间相互调用的中介者类,为了让系统具有更好的灵活性和可扩展性,通常还提供了抽象中介者,其结构图如图20-6所示:
图20-6 中介者模式结构图
在中介者模式结构图中包含如下几个角色:
● Mediator(抽象中介者):它定义一个接口,该接口用于与各同事对象之间进行通信。
● ConcreteMediator(具体中介者):它是抽象中介者的子类,通过协调各个同事对象来实现协作行为,它维持了对各个同事对象的引用。
● Colleague(抽象同事类):它定义各个同事类公有的方法,并声明了一些抽象方法来供子类实现,同时它维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信。
● ConcreteColleague(具体同事类):它是抽象同事类的子类;每一个同事对象在需要和其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信;在具体同事类中实现了在抽象同事类中声明的抽象方法。
中介者模式的核心在于中介者类的引入,在中介者模式中,中介者类承担了两方面的职责:
(1) 中转作用(结构性):通过中介者提供的中转作用,各个同事对象就不再需要显式引用其他同事,当需要和其他同事进行通信时,可通过中介者来实现间接调用。该中转作用属于中介者在结构上的支持。
(2) 协调作用(行为性):中介者可以更进一步的对同事之间的关系进行封装,同事可以一致的和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑,对同事的请求进行进一步处理,将同事成员之间的关系行为进行分离和封装。该协调作用属于中介者在行为上的支持。
在中介者模式中,典型的抽象中介者类代码如下所示:
abstract class Mediator { protected ArrayList<Colleague> colleagues; //用于存储同事对象 //注册方法,用于增加同事对象 public void register(Colleague colleague) { colleagues.add(colleague); } //声明抽象的业务方法 public abstract void operation(); }
在抽象中介者中可以定义一个同事类的集合,用于存储同事对象并提供注册方法,同时声明了具体中介者类所具有的方法。在具体中介者类中将实现这些抽象方法,典型的具体中介者类代码如下所示:
class ConcreteMediator extends Mediator { //实现业务方法,封装同事之间的调用 public void operation() { ...... ((Colleague)(colleagues.get(0))).method1(); //通过中介者调用同事类的方法 ...... } }
在具体中介者类中将调用同事类的方法,调用时可以增加一些自己的业务代码对调用进行控制。
在抽象同事类中维持了一个抽象中介者的引用,用于调用中介者的方法,典型的抽象同事类代码如下所示:
abstract class Colleague { protected Mediator mediator; //维持一个抽象中介者的引用 public Colleague(Mediator mediator) { this.mediator=mediator; } public abstract void method1(); //声明自身方法,处理自己的行为 //定义依赖方法,与中介者进行通信 public void method2() { mediator.operation(); } }
在抽象同事类中声明了同事类的抽象方法,而在具体同事类中将实现这些方法,典型的具体同事类代码如下所示:
class ConcreteColleague extends Colleague { public ConcreteColleague(Mediator mediator) { super(mediator); } //实现自身方法 public void method1() { ...... } }
在具体同事类ConcreteColleague中实现了在抽象同事类中声明的方法,其中方法method1()是同事类的自身方法(Self
systemUI之notification
好久没写东西,我得承认,是自己懒了。
解过几个statusbar的bug,觉得notification还是挺有意思的,分析一下流程,以作备忘吧。
- 通知的接收
1. notification由系统或第三方应用封装发出notificationManager.notify()。
2. 通知进入一个队列NotificationManagerService.enqueueNotificationInternal()。
3. 在上面方法里面会发现一个熟悉的身影,就是mStatusBar,它是StatusBarManagerService的化身。调用mBar.addNotification(key,notification);
4. 通过linux查找命令先定位IStatusBar.aidl的位置,然后在该最外路径下搜索IStatusBar.Stub可以找到具体实现它的java文件,这里我们找到了CommandQueue,java。然后调用CommandQueue. addNotification(),该方法利用handle发出一个消息:MSG_ADD_NOTIFICATION,跳转到回调函数addNotification(ne.key,ne.notification); PhoneStatusBar实现了这个回调方法。
5. 以上一个通知算是被系统所接收到。
- 通知的statusbar显示
public void addNotification(IBinder key, StatusBarNotification notification) { // 1.初始化一个状态栏图标来体现该notification StatusBarIconView iconView = addNotificationViews(key, notification); if (iconView == null) return; } if (immersive) { //无实际作用,4.1会被注释 } else if (notification.notification.fullScreenIntent != null) { // 2.not immersive & a full-screen alert should be shown,比如电话和闹钟的通知灰常nb Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); try { notification.notification.fullScreenIntent.send(); } catch (PendingIntent.CanceledException e) { } } else { // 3.usual case: status bar visible & not immersive。普通notification都走这道,用一个动画的形式显示该通知的文字信息。 tick(notification); } // 4.Recalculate the position of the sliding windows and the titles. setAreThereNotifications(); // 5.刷新一下ExpandedView的位置, updateExpandedViewPos(EXPANDED_LEAVE_ALONE); }
- 通知的expendView显示
代码都在上一步走完了。
条目的添加是addNotificationViews():
// 1.Construct the expanded view. NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
view的刷新是addNotification():
// 5.刷新一下ExpandedView的位置, updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
- 通知的更新
同样是从CommandQueue. updateNotification()开始走,然后到PhoneStatusBar. updateNotification()。代码流程和通知的添加几乎一致,只是没有add view这一步。
- 通知的发送
protected void sendNotification() { // TODO Auto-generated method stub Log.e(TAG, "-----sendNotifications----"); // 1.实例化intent和获取通知的服务。 Intent mIntent = new Intent(); NotificationManager notificationManager = (NotificationManager) mContext .getSystemService(Context.NOTIFICATION_SERVICE); mIntent.setClass(mContext, ShowHello.class); PendingIntent mPendingIntent = PendingIntent.getActivity(mContext, 0, mIntent, 0); // 2.设置通知的相应属性 // mNotification.fullScreenIntent = mPendingIntent;//这句话的作用是决定通知是否自动弹出那个可跳转的activity。 mNotification.defaults |= Notification.DEFAULT_SOUND;//设置通知是否播放声音。 mNotification.flags = Notification.FLAG_ONGOING_EVENT; // 在4.0的expendview里多显示一张图片,2.3系统会报错 mNotification.largeIcon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_action_search); // 显示通知调用下面的方法是必须的,但在api11会被deprecated,使用Notification.Builder代替。 mNotification.setLatestEventInfo(mContext, tick, TAG, mPendingIntent); // 3.唤醒通知 notificationManager.notify(R.drawable.ic_launcher, mNotification); }
- 各个主要版本的变化
分析时是以4.0为准,为了兼顾其他也顺便看了一遍2.3,4.1的流程,notification总的来说没有大的变化,API升级后有些方法被弃用有了新的实现,与之相关的就是状态栏为了适配pad和更高分辨率机型进行了一些重构,体现在我们这里就是2.3的statusBarService在4.0后改名为phoneStatueBar。4.0加入的immersive模式在4.1被彻底废除。
- 三言两语
Notification的前世来生也就这样,生平中有过纠结的是NotificationManager,NotificationManagerService,StatusBarManagerService,phoneStatueBar,CommandQueue。