享受代码,享受人生

SOA is an integration solution. SOA is message oriented first.
The Key character of SOA is loosely coupled. SOA is enriched
by creating composite apps.
posts - 213, comments - 2315, trackbacks - 162, articles - 45
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

为什么叫“老师” 和 “学生”

Posted on 2005-01-22 20:47  idior  阅读(...)  评论(...编辑  收藏

对于一个多类型的用户的应用,我们首先想到的是对用户进行抽象。

但是抽象的根据是什么? 行为!我们要根据不同类型的用户的行为来进行抽象。

 

我们仔细想想在一个多用户系统的应用,不同的用户之间的区别在于什么?

1.   具有共同行为,但做法不同   (学生,老师都可以查看成绩,但学生只能看到自己的)

2.   A有的行为 B 没有          (老师可以修改成绩,学生不能)

 

看到了学生老师这些字样,很容易就让我们去建立一个又一个Class,如下图所示:

 

 


对象不是名词。
如何建立和区分一个对象,最根本的在于它的行为,为什么你要建立一个老师类型?什么叫老师?老师和学生的区别在什么?这是依赖于User的具体行为的。 其实在考虑老师学生的时候,你考虑的是一个权限的问题。不是说User是不是老师,而应该说User是否具有老师的权限。

 

那么这个对象的体系如何建立?

现在我们有以下的需求:

1.       User有一系列的行为。                                         (查成绩,改成绩)

2.       User的某些行为根据角色的不同,做法也有所不同。               (查成绩)

3.       不同角色的User可能有其他角色所没有的行为。                   (改成绩)

4.       最终我们要创建并使用User

 

那么我们就需要在满足上面需求的情况下建立User的体系结构。下面我们一点一点的来说明。

第一点说明不是一个行为,如果只有一个行为,那么我们从User继承老师学生类,通过简单的多态就可以实现他们的区分。也就是说如上图所示的类结构就已经满足我们的需求。但是通常情况下User是不会只具有一个行为的。

第二点说明对应于一个行为可以有两种做法,那么我们将这个行为单独抽成一个类,通过这个类来实施这个行为,然后不同的角色通过继承这个类来实现多态。

第三点和第二点相似,是它的一个特殊情况。在继承的时候我们只要给一个空的实现就可以了。这其中包含了(null object模式)

 

如果以上的话让你不是很清楚的话,就看一下下面的UML图吧:

 

 


实现代码如下


namespace TestStack
{
    
public class User 
    
{
        
public void SetUpdateImpl(IUpdateImpl iu) 
        
{
            updateImpl
=iu;
        }


        
public void SetQuertImpl(IQueryImpl iq) 
        
{
            queryImpl
=iq;
        }


        
protected void Update() 
        
{
            updateImpl.Update();

        }


        
protected void Query() 
        
{
            queryImpl.Query();
        }


        
///
        
///<link>aggregationByValue</link>

        private IQueryImpl queryImpl;
        
///
        
///<link>aggregationByValue</link>

        private IUpdateImpl updateImpl;
    }


    
Query

    
Update
}


类结构图已经做出来了,那么第四点需求如何实现呢?目前的结构为第四点需求的实现,打下了良好的基础.

在建立好多用户的类结构之后,自然要解决最后的问题:创建并使用
User。

 

随风的随笔中提到了注册,但是显然我们不应该将注册作为用户的主要行为,用户的责任不应该是为了注册吧。既然如此,那么IRegister这个抽象就显的不太合理。

 

Wayfarer在他的评论中提到了用一个wrapper来为用户实现IRegister,似乎是一个解决方法。你可以在看完本文后,再来比较一下我的方案和wayfarer的方案。

 

其实注册这个问题是一个创建User对象的问题,创建自己的工作当然应该交给别人来完成比较好。所以实现IRegister之类的方法并不是一个好的选择,那么交给谁来完成呢?既然想不到,就交给一个创建对象吧。

这个对象的任务就是创建一个User。你想到了什么?其实这就是一个Command对象。将一个请求封装成一个对象,这是Command模式的基本特征。而且在这里command模式还可以让我们实现事务处理。 


 


那么我们如何创建一个
User,比如我们要创建一个具有老师权限的User。用代码说明问题:

 

using System;

namespace TestStack
{

    
public interface ICommand
    
{
        
void Execute();
    }


    
public class RegisterUserCommand:ICommand
    
{
        
public void Execute()
        
{
            User user
=new User();

            IUpdateImpl iu
=GetUpdateImpl();
            IQueryImpl  iq
=GetQueryImpl();
             
            user.SetQuertImpl(iq);
            user.SetUpdateImpl(iu);

            
//put this user into database
        }


        
protected virtual IUpdateImpl GetUpdateImpl()
        
{
            
return new StudentUpdate();   //  create a student default
        }


        
protected virtual IQueryImpl GetQueryImpl()
        
{
            
return new StudentQuery();   //  create a student default
        }


    }


    
public class RegisterTeacherCommand :RegisterUserCommand    
    
{
        
protected override IUpdateImpl GetUpdateImpl()
        
{
            
return new TeacherUpdate();   //  create a teacher
        }


        
protected override IQueryImpl GetQueryImpl()
        
{
            
return new TeacherQuery();   //  create a teacher
        }

    }

}

 

如果想创建一个可以查看所以成绩而不能修改成绩的用户呢(比如校长)?很简单

 

 

    public class RegisterMasterCommand :RegisterUserCommand    
    
{
        
protected override IUpdateImpl GetUpdateImpl()
        
{
            
return new StudentQuery();   //  create a student
        }


        
protected override IQueryImpl GetQueryImpl()
        
{
            
return new TeacherQuery();   //  create a teacher
        }

    }

 

在前面的类结构的基础上,只要复写两个Get方法你就可以任意组合出不同权限的User

 

由此我们得到了一个很容易扩展的用户结构。

 

这个例子是从现实的问题中派生出来的,其实在不知不觉中已经运用到了很多的模式,设计模式就是用来解决问题的,知道如何使用它们才是学习模式的关键,希望本文可以让你有所体会。