浅谈MVC,MVP 和 MVVM 的区别

复杂的软件必须有清晰合理的架构,否则无法开发和维护。

以下以Javascript客户端页面开发为例使用图示简单阐述三者的联系和区别。

需要注意的是,MVC开发模式备广泛用于各种软件开发中,包括互联网的B/S模式的产品,而其他两种模式大多数用在客户端开发中,例如:Javascrtipt、WPF、Adnroid开发等等。
Continue reading “浅谈MVC,MVP 和 MVVM 的区别”

进攻式编程 与 防御式编程

1、防御式编程
业务的流转应该在参数的正确性下进行。简言之,就是先进行安全性或者存在性检查,然后再执行业务流程。
防御式编程方式例如:DATABASE需要对目标表进行两次扫描,一次是存在性检查,一次为执行业务(如果参数正确的话)。
防御式编程的思想为:在没有真正的操作数据之前,要保证所有的操作或者参数都是正确的,DATABASE只做正确的事。程序编写者应该尽量的预料出可以预料到的错误。我们不应该认为,在表中添加了check约束,就不用在程序中判断某个人的性别只能是男和女。

2、进攻式编程
一般情况下,调用环境已经把要传入程序的参数进行了验证以保证参数是正确的或者大部分是正确的,而此时再采用防御式编程无疑浪费了资源和时间。貌似这个时候采用进攻是编程是正确英明的选择。
先不管参数正确与否,先进行业务操作,在出现错误的时候再进行处理。

 

防御式多用在需要给其他人使用的接口上,
进攻式多用在自己可以掌控的程序开发中。

 

契约式编程

契约式编程是编程的一种方法。那么什么是契约式编程呢?我想这个概念是从“合同”演变过来的。

在人类的社会活动中,契约一般是用于两方,一方(供应者)为另一方(客户)完成一些任务。每一方都期待从契约中获得利益,同时也要接受一些义务。通常,一方视为义务的对另一方来说是权利。契约文档要清楚地写明双方的权利与义务。

契约合同能保障双方的利益,对客户来说,合同规定了供应者要做的工作;对供应者来说,合同说明了如果约定的条件不满足,供应者没有义务一定要完成规定的任务。

同样的道理也适合于软件。设想一个软件单元E。它要达到它的目的(履行契约), E使用的策略可能会包括一系列的子任务,t1, … tn。如果子任务ti 不是那么简单的,它得调用另一个功能例程(routine)R。换句话说,E把子任务转包给R。这样的情形应该被一个很好定义的“登记表”(roster)来管理双方的义务与权利--契约。

简单的说,就是你不给我想要的东西,我就不干活。

Continue reading “契约式编程”

防御式编程

什么是防御式编程 ?

顾名思义,防御性编程是一种细致、谨慎的编程方法。为了开发可靠的软件,我们要设计系统中的每个组件,以使其尽可能地“保护”自己。我们通过明确地在代码中对设想进行检查,击碎了未记录下来的设想。这是一种努力,防止(或至少是观察)我们的代码以将会展现错误行为的方式被调用。

在软件开发过程中,不可避免的会遇到错误处理,而且这部分对于整个软件的健壮性有非常大的作用,它是软件除了功能性以外最重要的指标了,一个软件成功与否与其健壮性有很大的联系。我在以前的开发中也时常思考错误处理,因为这部分代码逻辑比较不容易梳理清楚。以异常的处理为例,以前通常就采用比较简单粗暴的处理方式:用try..catch加Exception把所有异常都包起来,这样简单省事,写的代码最少,相信很多童鞋曾经跟我一样写过这样的代码,很明显,这样写有很大的问题,最主要的问题在于:

  • Exception会吃掉所有可以处理的异常,使得对于某些我们关心的异常无法捕获,因为对于不同的异常我们可能需要做不同的处理,有些可以在本函数内处理掉,有些需要提示用户(例如文件不存在,网络无法访问),有些需要告诉上一层代码该如何处理,所有这些在直接用Exception处理异常时都无法做到,简而言之就是无法做到异常的精细化处理

那么怎么做才好呢?这部分代码真不少,虽然无关软件功能性,但是确是健壮性的基础。具体如何处理这些没有完全标准的答案,软件设计本来就是一项带有艺术色彩的智力劳动,没有一劳永逸的解决方案,最关键的在于掌握好基础知识,因地制宜地采取措施。下面主要谈谈实现健壮性的基本技术,基本的实现软件健壮性的技术有以下几种:

  • 断言
  • 错误处理
  • 异常
  • 从设计上简化异常处理的技术;隔离程序
  • 辅助调试的代码(print打印之类的小段函数)

Continue reading “防御式编程”

熔断器(Circuit Breaker)设计模式

如果大家有印象的话,尤其是夏天,如果家里用电负载过大,比如开了很多家用电器,就会”自动跳闸”,此时电路就会断开。在以前更古老的一种方式是”保险丝”,当负载过大,或者电路发生故障或异常时,电流会不断升高,为防止升高的电流有可能损坏电路中的某些重要器件或贵重器件,烧毁电路甚至造成火灾。保险丝会在电流异常升高到一定的高度和热度的时候,自身熔断切断电流,从而起到保护电路安全运行的作用。

同样,在大型的软件系统中,如果调用的远程服务或者资源由于某种原因无法使用时,如果没有这种过载保护,就会导致请求的资源阻塞在服务器上等待从而耗尽系统或者服务器资源。很多时候刚开始可能只是系统出现了局部的、小规模的故障,然而由于种种原因,故障影响的范围越来越大,最终导致了全局性的后果。软件系统中的这种过载保护就是本文将要谈到的熔断器模式(Circuit Breaker) Continue reading “熔断器(Circuit Breaker)设计模式”

CAP原理和BASE思想

分布式领域CAP理论
Consistency(一致性), 数据一致更新,所有数据变动都是同步的
Availability(可用性), 好的响应性能
Partition tolerance(分区容错性) 可靠性

定理:任何分布式系统只可同时满足二点,没法三者兼顾。
忠告:架构师不要将精力浪费在如何设计能满足三者的完美分布式系统,而是应该进行取舍。

Continue reading “CAP原理和BASE思想”

PHP设计模式 – 服务定位器模式(Service Locator)

1、模式定义

当系统中的组件需要调用某一服务来完成特定的任务时,通常最简单的做法是使用 new 关键字来创建该服务的实例,或者通过工厂模式来解耦该组件与服务的具体实现部分,以便通过配置信息等更为灵活的方式获得该服务的实例。然而,这些做法都有着各自的弊端:

1)、在组件中直接维护对服务实例的引用,会造成组件与服务之间的关联依赖,当需要替换服务的具体实现时,不得不修改组件中调用服务的部分并重新编译解决方案;即使采用工厂模式来根据配置信息动态地获得服务的实例,也无法针对不同的服务类型向组件提供一个管理服务实例的中心位置;

2)、由于组件与服务之间的这种关联依赖,使得项目的开发过程受到约束。在实际项目中,开发过程往往是并行的,但又不是完全同步的,比如组件的开发跟其所需要的服务的开发同时进行,但很有可能当组件需要调用服务时,服务却还没完成开发和单体测试。遇到这种问题时,通常会将组件调用服务的部分暂时空缺,待到服务完成开发和单体测试之后,将其集成到组件的代码中。但这种做法不仅费时,而且增大了出错的风险;

3)、针对组件的单体测试变得复杂。每当对组件进行单体测试时,不得不为其配置并运行所需要的服务,而无法使用Service Stub来解决组件与服务之间的依赖;

4)、在组件中可能存在多个地方需要引用服务的实例,在这种情况下,直接创建服务实例的代码会散布到整个程序中,造成一段程序存在多个副本,大大增加维护和排错成本;

5)、当组件需要调用多个服务时,不同服务初始化各自实例的方式又可能存在差异。开发人员不得不了解所有服务初始化的API,以便在程序中能够正确地使用这些服务;

6)、某些服务的初始化过程需要耗费大量资源,因此多次重复地初始化服务会大大增加系统的资源占用和性能损耗。程序中需要有一个管理服务初始化过程的机制,在统一初始化接口的同时,还需要为程序提供部分缓存功能。

要解决以上问题,我们可以在应用程序中引入服务定位器(Service Locator)模式。

服务定位器(Service Locator)模式是一种企业级应用程序体系结构模式,它能够为应用程序中服务的创建和初始化提供一个中心位置,并解决了上文中所提到的各种设计和开发问题。

服务定位器模式和依赖注入模式都是控制反转(IoC)模式的实现。我们在服务定位器中注册给定接口的服务实例,然后通过接口获取服务并在应用代码中使用而不需要关心其具体实现。我们可以在启动时配置并注入服务提供者。

如果你了解 Laravel 框架,你对这一流程会很熟悉,没错,这就是 Laravel 框架的核心机制,我们在服务提供者中绑定接口及其实现,将服务实例注册到服务容器中,然后在使用时可以通过依赖注入或者通过服务接口/别名获取服务实例的方式调用服务。 Continue reading “PHP设计模式 – 服务定位器模式(Service Locator)”

PHP设计模式 – 依赖注入模式(Dependency Injection)

1、模式定义

依赖注入(Dependency Injection)是控制反转(Inversion of Control)的一种实现方式。

我们先来看看什么是控制反转。

当调用者需要被调用者的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例,但在这里,创建被调用者的工作不再由调用者来完成,而是将被调用者的创建移到调用者的外部,从而反转被调用者的创建,消除了调用者对被调用者创建的控制,因此称为控制反转。

要实现控制反转,通常的解决方案是将创建被调用者实例的工作交由 IoC 容器来完成,然后在调用者中注入被调用者(通过构造器/方法注入实现),这样我们就实现了调用者与被调用者的解耦,该过程被称为依赖注入。

依赖注入不是目的,它是一系列工具和手段,最终的目的是帮助我们开发出松散耦合(loose coupled)、可维护、可测试的代码和程序。这条原则的做法是大家熟知的面向接口,或者说是面向抽象编程。 Continue reading “PHP设计模式 – 依赖注入模式(Dependency Injection)”

Laravel 服务容器 – 控制反转(IoC)和依赖注入(DI)

容器,字面上理解就是装东西的东西。常见的变量、对象属性等都可以算是容器。一个容器能够装什么,全部取决于你对该容器的定义。当然,有这样一种容器,它存放的不是文本、数值,而是对象、对象的描述(类、接口)或者是提供对象的回调,通过这种容器,我们得以实现许多高级的功能,其中最常提到的,就是 “解耦” 、“依赖注入(DI)”。本文就从这里开始。

Continue reading “Laravel 服务容器 – 控制反转(IoC)和依赖注入(DI)”