I come, I see, I conquer

                    —Gaius Julius Caesar

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

1. 单例模式(Singleton)

   我的故事:最近我在使用一个赚取积分的软件,只要用申请的帐号登录后,就可以获得积分,足够的积分就可以在网上直接兑换成小玩具,巧克力和糖果。于是我申请了很多帐号,并让它们同时登录,我想这是个不错的主意,因为多个帐号同时登录就可同时赚取积分获得更多的糖果了,哈哈哈。。。。直到有一天。。。。。。。。。

   思路:由于一个类只能有一个实例,所以不能直接用构造函数来生成实例。我们想到的是向外提供一个公有方法,在该方法中判断实例的存在,决定是否生成实例。怎么访问这个方法呢?让我想想。。。。嗯。。。我们不是可以把它声明为static方法吗,这样就可以直接通过类来访问了。

   方法:(1) 要使构造函数不被用来生成实例,必须将它的public访问控制改成private或者protected。

            (2) 公有方法的作用:判断是否存在一个实例,如果存在则返回该实例,否则创建一个实例。因些它返回类的实例。由于被调用前没有形成实例,必须把该方法声明为static类型的,通过类名来调用。

            (3) 类中必须有一个保存该实例的类变量。同理声明为static类型,使它和实例脱勾。

   实例列举:你可以打开多个记事本,但不管你按多少次的Ctrl+Alt+Del,你也只能打开一个windows任务管理器 

using System;
using System.Collections;

class TaskManageWindow
{
    
private static TaskManageWindow instance; // (3) 声明一个私有的静态变量,保存类的实例

    
protected TaskManageWindow() // (1) 限制构造函数访问权限,也可声明为private
    {
        
    }
    
public static TaskManageWindow GetInstance() // (2) 公有的静态方法决定是否创建类实例
    {
        
if (instance == null//还没有任何实例则创建一个实例
        {
            instance 
= new TaskManageWindow();
        }
        
return instance; //已存在实例则返回该实例
    }
}
class Client
{
    
static void Main(string[] args)
    {
        TaskManageWindow w1 
= TaskManageWindow.GetInstance();
        TaskManageWindow w2 
= TaskManageWindow.GetInstance();
        TaskManageWindow w3 
= TaskManageWindow.GetInstance();

        
// 判断是否为同一个实例
        if ((w1 == w2) && (w2 == w3))
            Console.WriteLine(
"The same window!");

        Console.Read();
    }
}

 

输出:

The same window!

 

注意:以上实例只用于单线程环境。对于多线程环境,必须加锁处理或信号量处理。

 

2. 观察者模式(Observer)

   现实生活中的例子:多个用户订阅了小李在Youtube上的视频,当有新的视频上传,系统自动发邮件通知各个订阅者。

   思路:该模式讲述的是一种多对一的依赖关系,当一件事物发生变化,依赖于该事物的其它所有事物应该作出反应。主题发生变化,则通知相关的订阅者。这样,主题必须维护一群订阅者,在主题类中用ArrayList来存储。通知这个动作针对的是每一个订阅者,用foreach可以办到,且该动作是因主题变化而触发的。订阅者除了对主题的变化表示响应外完全可以不做其它事情。

   例子实现: 

using System;
using System.Collections;

abstract class Subject
{
    
private string name;

    ArrayList subscriber = 
new ArrayList(); //该主题维护的一系列订阅者

    
public Subject(string name)
    {
        
this.name = name;
    }

    
public void Attach(VideoSubscriber vsub) //加入订阅者
    {
        subscriber.Add(vsub);
    }

    
public void Detach(VideoSubscriber vsub) //删除订阅者
    {
        subscriber.Remove(vsub);
    }

    
public void NotifySubscriber() //一一通知订阅者(调用订阅者列表中订阅者的响应函数 )
    {
        
foreach (VideoSubscriber sub in subscriber)
            sub.Response();
    }

    
public void AddNewVideo() //主题发生变化
    {
        NotifySubscriber();
    }
}

class Releaser : Subject //具体的主题,本例中即发布者
{
    
public Releaser(string name)
        : 
base(name)
    { }
}

interface ISubscriber //抽象的订阅者
{
    
void Response();
}

class VideoSubscriber : ISubscriber //具体的订阅者,视频订阅者
{
    
private string name;

    
public VideoSubscriber(string name)
    {
        
this.name = name;
    }

    
public void Response() //当发布者发生变化时,订阅者需要作出的反应
    {
        Console.WriteLine(
"{0}收到视频更新消息!",name);
    }
}

class Client
{
    
static void Main(string[] args)
    {
        Releaser rls 
= new Releaser("小李");
        VideoSubscriber subscriber1 
= new VideoSubscriber("subscriber1");
        VideoSubscriber subscriber2 
= new VideoSubscriber("subscriber2");
        VideoSubscriber subscriber3 
= new VideoSubscriber("subscriber3");

        
//将各订阅者加入到发布者管理的订阅者列表中,也称为“注册”。
        rls.Attach(subscriber1);
        rls.Attach(subscriber2);
        rls.Attach(subscriber3);
        rls.AddNewVideo();

        
//将一个订阅者从发布者管理的订阅者列表中删除
        rls.Detach(subscriber3);
        rls.AddNewVideo();

        Console.Read();
    }
}

 

输出:

subscriber1收到视频更新消息!
subscriber2收到视频更新消息!
subscriber3收到视频更新消息!
subscriber1收到视频更新消息!
subscriber2收到视频更新消息!

      当我们掌握了该模式中的角色和要素,换换类名和方法名,改写一下方法中的内容,就能轻而易举地模仿生活中的观察者模式。如:班上要搞活动,班长将通知班上的各个同学作些准备;将我的宝马开到A宾馆,负责看车的工作人员说,一有情况就通知你。每个房间都装上了烟雾传感器,意外情况时,控制中心的警报器发出警报。

 

posted on 2008-09-20 11:15  jcsu  阅读(584)  评论(0)    收藏  举报