论软件体系结构设计中系统质量属性的实现

软件质量的好坏,不仅要看系统是否能满足客户的功能性要求,也要看其是否能满足客户的非功能性要求,系统非功能性用质量性来描述,与软件体系结构设计相关的系统质量属性主要有 可用性、可修改性、性能、安全性、可测试性和易用性 ,在软件体系结构的设计过程中,为了使系统的设计方案能保证某种特定的质量属性和实现,需要采用一些针对性的具体设计策略,例如,对可用性质量属性,为了阻止错误发展成为故障或者为了恢复错误,往往采取主动冗余或被动冗余的设计决策,对于可修改性质量属性,为了提高系统的可修改和扩展性,往往采取局部化修改的设计策略等等。

软件体系结构质量属性:

成功的企业体系结构必须具备各种各样的质量属性。它可以帮助预先定义这些属性。这个属性集构成了一个蓝图,以指导分析、设计、编码、部署、维护、更新等阶段的工作。这种体系结构是对成型后的系统的预想。典型的质量属性包括(但并不局限于此)下列方面:

可修改性 (Modifiability) : 有了这种特性就可以很容易地对基础软件进行修改  ,是指能够快速地以较高的性价比对系统进行变更的能力。

质量属性 虽然不是系统的功能需求, 但是 用户的这些要求达不到,最终会要求 拒绝使用我们所提供的系统的 如何满足 这样的非功能需求 呢? 上面 所提到 的各个属性都是相互制约的,都会对系统产生消极的影响,甚至相互是矛盾的,就要求我们怎么去取舍,在构架的设计中去折中处理。

修改性 :其实还是代码的质量问题,让架构对程序员写的代码做约束,限制程序员的随意性 我们邮政储蓄系统采用了 客户机 - 服务器 ( C/S )的软件体系结构的设计。

 

为了使系统具有可修改性和可伸缩性,系统被分成客户机和服务器两个部分;有(很大)一部分计算是在服务器部分执行的,服务器可以在不依赖客户机的情况下进行修改,并可为多个客户机提供服务。

 

一、局部化修改——目标是减少由某个变更直接影响的模块的数量;

1、预期期望的变更(expected changes ):

确保canVote() 方法返回true或者false, 同时你也能写一个测试用来验证这个方法抛出的IllegalArgumentException异常。

public class Student {
 
  public boolean canVote(int age) {
      if (i<=0) throw new IllegalArgumentException("age should be +ve");
      if (i<18) return false;
      else return true;
  }
}

Guava类库中提供了一个作参数检查的工具类--Preconditions类,也许这种方法能够更好的检查这样的参数,不过这个例子也能够检查

 

2、维持语义一致性(semantic coherence ):

3、泛化模块(Generalize the module ):

4、限制选择参数(Limit possible options ):

 

二、防止连锁反应——目标是限制对局部化的模块的修改,以防止对某个模块的修改间接地影响到其他模块;

 

尽量维持现有接口或类的名字等不变,把要改动的模块尽量降到最低。推迟绑定时间在我的系统中还没有体现出来。

维持语义的一致性是保证模块中不同责任之间可以协同工作,不要太多的依赖于其他的模块。

1、信息隐藏(Hide information ):

2、维持现有接口(Maintain existing interfaces ):

3、限制通信路径(Restrict communication paths ):

4、使用仲裁者(Use an intermediary ):

 采用迪米特法则可以有效防止连锁反应:

例子:

在美国电影《教父》中,教父如果为了除掉对手,会亲自动手吗?肯定不,教父会安排手下人处理。教父这样位高权重的人,会直接跟杀手安排任务吗?一般不会,他会跟手下的心腹说明,然后由手下人去执行。

这样一来,我们看看,先看看三个普通角色,被杀的人Person,杀手Killer,心腹CoreMember,如下:

/**
 * 某个人
 * @author ljtyzhr
 *
 */
public class Person{
    public String name;
}
 
/**
 * 杀手
 * @author ljtyzhr
 *
 */
public class Killer{
     public void kill(Person someone){
         System.out.println(someone.name+"被杀死了");
     }
}
 
/**
 * 教父身边的核心人员
 * 
 * @author ljtyzhr
 *
 */
public class CoreMember{
    private Killer killer;
}

事实上,核心人员直接与杀手打交道,教父只会与心腹打交道,如此,关系应该如下:

 

/**
 * 教父身边的核心人员
 * 
 * @author ljtyzhr
 *
 */
public class CoreMember{
    private Killer killer;
    public void kill(Person someone){
              killer.kill(someone);
    }
}

家父持有对核心人员的引用,如下:

/**
 * 教父
 * @author ljtyzhr
 *
 */
public class GodFather{
     CoreMember coremember;
     
     public void kill(Person someone){
           Killer killer = new Killer();
           killer.kill(someone);
     }
}

 

 

 

 

三、延迟绑定时间——目标是控制部署时间并允许非开发人员进行修改。

1、运行时注册(Runtime registration):

2、配置文件(Configuration files):

3、多态(Polymorphism):

4、组件更换(Component replacement ) :

5、遵守已定义的协议(Adherence to defined protocols) :

 

延时0.5秒后发送一个网络请求,首先想到了handler,结果出现这么一个错误,解决方案很简单,就是在线程里调用Looper.prepare(),然后调用Looper.loop()就可以了

private void sendMessageToClient(final StringBuilder s){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                sendToClient.sendDataToClient(s,clientSocketAddress);//网络请求必须在子线程
            }
        }).start();

    }

 

 posted on 2020-03-02 11:51  Aurinko  阅读(477)  评论(0编辑  收藏  举报