精华内容
下载资源
问答
  • Spring家族大件

    千次阅读 2018-12-03 18:31:07
    Spring家族很庞大,从最早先出现的服务于企业级程序开发的Core、安全方面的Security、到后来的作为各种数据源桥梁的Data、最近年很火的Boot,以及最新推出的正在蓬勃发展的Cloud(在本文之后都简单称为Boot、Clo.....

    作者:powerzhuye(本文经作者授权发布)

    出处:https://juejin.im/user/5ba37b9de51d450e7428affe

    Spring家族很庞大,从最早先出现的服务于企业级程序开发的Core、安全方面的Security、到后来的作为各种数据源桥梁的Data、最近几年很火的Boot,以及最新推出的正在蓬勃发展的Cloud(在本文之后都简单称为Boot、Cloud省略Spring节省一点我的打字时间?)。

    上面这个脑图给出了Spring家族主要的一些成员,右侧非Cloud部分列的是功能,左侧Cloud部分虽然组件繁杂,但是结构清晰(确实新版本清晰多了,命名也统一,你可以放大图片看一下这些是否熟悉),所以更进一步列出了组件要的一些模块依赖和开启功能的主注解。

    我说Spring的发展

    Spring框架几乎涉及到了Java企业级服务开发的所有方面,也几乎针对所有开发常用的模式、中间件、数据库进行了整合适配。

    之前在聊互联网架构模式的时候我谈到过,很多时候我们写一个业务把逻辑写死写出来是比较容易的,但是把这个逻辑提取成模式进而打包成一个框架来给大家使用,这是比较难的。因为我们只有经历过足够多的场景后才能提取出普适的功能框架,大部分人才能用上,而且我们需要针对核心功能开放出可配置的部分,满足小部分人进一步定制和扩展功能的需要。

    Spring框架经历了几个阶段:

    1.第一个阶段推出的Core、Security、Data是把单体应用开发服务好。不仅仅提供了便捷的数据库访问、Web MVC等必要功能,而且通过AOP、IOC两大利器让我们的程序内在能够做到低耦合可扩展。

    2.第二个阶段推出的Boot的意义不仅仅是加速了开发效率而且能让我们的程序从可用变为好用,应用程序核心业务逻辑可能只有70%的工作量,要让程序在线上跑的愉快还有30%的监控日志打点等工作量需要去做。

    3.第三个阶段推出的Cloud的意义在于推动了微服务架构的落地。让不具备开发微服务基础套件的小型互联网公司也能享受到免费的开箱即用的微服务解决方案。其实很多人不是看了微服务的架构思想去寻找解决方案,而是了解到了Spring Cloud才去了解微服务思想从而落地的。

    4.目前属于第四个阶段,大力发展Cloud Dataflow+容器。Dataflow的思想是不管是做实时消息处理的服务还是临时运行的任务,都可以认为是服务的组件,如果可以有一套DSL来定义这些组件之间的交互方式,然后在容器中进行自由组合、部署、伸缩,那么架构会非常灵活。下图是Dataflow管理界面的一个示意图。

    Spring的发展可以看到互联网架构的发展,Spring给我们带来相当多的技术启发,从软件设计模式的启发慢慢到了架构的启发,甚至我觉得Spring是为Java开发打造了架构风格的模板,接下去Spring继续发展2到3年有望成为架构标准,我在想这个时候应用架构师何去何从?

    我说Spring Core

    Spring Core提供的IOC、AOP功能已经变为半个Java命根子了。其实很多开发平台并不是那么强调IOC和AOP,甚至有的平台完全没有相关支持。虽然我一直觉得IOC和AOP是非常好的思想,可以让我们的软件内部做到组件之间的低耦合,容易替换,容易扩展,但是我的观点是,作为一个类库不应该把自己组件的初始化以及组装工作交给外部来做。我们知道通过IOC容器来管理我们组件的实例化和依赖,其实我们可以在程序内部实现每一个组件,把装配工作交给XML配置进行,但是对于一些复杂的组件,如果这个工作的配置交给XML进行,那么也就相当于交给了使用者进行,相当于需要使用者一定要理解组件内部的装配结构,这是不合理的。更合理的方式是,组件或框架的作者提供一些扩展点,让使用者可以明确通过API来注入自己的扩展组件或实现组件,而对于只需要简单使用组件的使用者可以无需配置开箱即用。

    当然,这不是说Spring的IOC和AOP有什么不好,正因为框架实现的如此灵活,Java使用Spring作为容器也基本是标准了,所以Java界很多框架也因此可以相互进行很好的集成,确实是一个很好的平台。

    Spring 5推出了Reactive非阻塞技术栈,基于Netty或Servlet 3.1+容器,提供了Stream API、WebFlux以及各种响应式的存储(各种NOSQL)访问类库。从前到后实现非阻塞的服务,可以避免IO阻塞占据线程,减少线程切换和资源使用,以最小的资源做到最大化的并发。可惜的是JDBC目前并没有非阻塞的版本,这样我们主流的基于MySQL的应用并不能进行全链路(从Controller到外部的Rest服务到数据库)的非阻塞IO(一竿子到底这样才是最爽的)。而且对于Reactive套件,我经过简单的使用个人感觉API比较晦涩,链式调用可读性并不高,而且反而遇到了并发的一些坑,加上代码的示例和最佳实践现在也很少,我感到现在使用并不是特别成熟。

    我说Spring Data

    Spring Data希望以相对比较一致的Template API来让我们更方便得使用各种数据存储。我个人不太喜欢习惯使用Data套件而是更喜欢使用各种NOSQL的Java原生客户端。几个原因:

    1.原生客户端紧跟服务端的实现,可以第一时间体验到最新的功能

    2.原生客户端的API和服务端提供的API往往一一匹配,可以一竿子到底,让我们功能使用更准确

    3.原生客户端往往只是基于API的简单封装,性能更好

    当然,如果我们只是对NOSQL进行简单使用的话,Spring Data可能使用起来更方便。

    我说Spring Boot

    稍微老一点的Java开发基本都是从纯XML配置到XML+注解配置走过来的,比较有意思的是很多开发虽然当初在使用XML配置,但是往往问他们每一个配置的含义都不能准确回答出,基本就是拿着主管或前人搭建的一套XML配置直接复制粘贴过来使用。从侧面说明了,其实我们大部分那些Mybatis、Spring MVC的配置都是在干组件初始化而不是定制化的事情。从0开始要让一个组件用起来就需要这些基本的配置,既然是这样的话,其实完全可以有默认配置,采用约定大于配置的方式来做。只有在我们需要针对组件进行定制化的时候才去做更多配置。

    Spring Boot不但在自动配置、配置简化上做了很多工作,而且还提供了轻量的嵌入式的容器,只需要20行的Pom+10行代码,就可以立即实现一个可以自启的应用程序(部署简单)激发了我们使用微服务的热情。此外也给我们做了很多Production-ready的启示(Actuator),告诉我们一个完善的应用程序应当注重环境切换、监控、日志、打点等等方面。总之,之前我们可能需要半天时间搭建一个项目,现在通过start.spring.io甚至只需要10秒。在有Boot之前,我实在没有兴趣使用重量级的Java(可能就为了访问下数据库做一些处理,还是使用Python算了)来创建一个实验性的控制台应用程序。

    我说Spring Cloud

    上图来自官网首页,很好地阐述了各个组件之间的关系。我们来逐一过一下脑图上的那些组件:

    1.配置管理Cloud Config:提供了客户端和服务端,客户端的使用方式和Spring完美结合,服务端提供了Git方式和文件方式的数据存储,最新版本也提供了数据库方式。这个配置管理的功能上和之前《朱晔的互联网架构实践心得S1E5:不断耕耘的基础中间件》一文中我探到的那些配置管理的功能差十万八千里。

    2.服务发现Netflix Euerka:提供可客户端和服务端(兼管理台),这里的客户端是指服务发现的使用方,其实微服务中的服务在这里是客户端。

    3.断路器Netflix Hustrix:提供了客户端API、聚合服务端Tubine和Dashboard网站。

    4.服务网关:有Netflix Zuul和Cloud Gateway两种网关可以选择,后者据说性能更好。网关其实就是典型的Filter+Handler的实现机制,通过路由找到合适的Handler,然后调用Pre和Post的各种插件式Filter。

    5.调用链跟踪Cloud Sleuth:可以搭配Zipkin使用,功能只能说凑活用。Zipkin的那后台功能上和国内主流互联网实现的Trace后台功能相比还是太弱了。

    6.消息驱动Cloud Stream:抽象成为了产出消息的Source,消费数据的Sink和抓换数据的Processor。然后把Broker的实现通过Binder进行解耦,支持主流的Kafka、KafkaStream和RabbitMQ三种类型。

    7.消息总线Cloud Bus:抽象了MQ的功能,支持主流的MQ产品。

    8.函数即服务Cloud Function:把函数封装为Web服务或Stream服务可以独立调用。对函数编程的Function、Consumer和Supplier分别映射成为了Processor、Sink和Source。

    9.微服务契约Cloud Contract:实现契约优先的编程,可以先定义契约对契约进行测试,同时进行服务实现。复杂的服务可以用这套方式来做,消费者提供者对着契约自己编自己的,两不耽误。

    10.任务框架Cloud Task:非定时任务的概念,这里的任务是指一次性运行的进程。框架提供了任务执行审计管理最基本的功能。这里的任务最后可以在Cloud Dataflow中运行也可以独立运行。

    11.管理台:这里列的Admin管理台是第三方提供的,基于Actuator的端点进行信息的综合展示和监控。

    总结一下,总体上我感觉Cloud模块化的思想很好,模块和模块之间可以相互搭配使用,但是可能一开始没有进行系统性的规划,版本的升级带来的Breaking Changes有点过多,而且因为内容太多了,文档方面没有特别全面,要全部用起来坑会比较多,需要享受新功能的话还需要不断更新框架版本不断踩坑。

    从目前功能的完善程度来说我感觉核心功能完善度在60%(大概还需要发展1年可以用的比较舒服)。后台方面过于简陋,官方提供的后台零散丑陋而且完成度极低(相比国内一线互联网在治理这块开发的功能来说,完善度大概在30%,大概还需要发展2年可以用的比较舒服,如果可以好好规划一套完整的后台把服务治理所有相关功能都整合在一起就好了)。不管怎么样,至少Cloud套件是一套完整的解决方案,目前来看还没有可以媲美的其它开源选择可以使用(Dubbo我们也知道虽然现在又开始高速迭代,但是由于其原始定位是RPC框架,理念上还是有很多不同的,组件方面并没有Cloud那么完善)。

    除了功能不完善,Cloud令我担心的还有一点是(我没测试过,但是因为看到目前功能的迭代速度对这方面信心不足,谁大规模应用了能否可以给点数据),这些中间件(服务发现、网关服务、链路跟踪、配置管理)是不是经过压测,是否可以满足比较大的压力,如果只是实现功能的话,可能会在全面用起来后遇到性能瓶颈,在这个时候恐怕就麻烦了。

    总结

    Spring家族已经是功能强大的庞然大物了,我们的项目pom中出现几十个Spring依赖也是家常便饭。使用.NET家族的套件也是几年前的事情了,但是至今我还是觉得微软.NET的开发套件不管是MVC还是ORM还是RPC方面比Spring的MVC、Data JPA(现在大家都使用Mybatis,Mybatis也还是太弱了)、Cloud套件在功能和设计的优雅上更胜一筹,希望将来可以看到Spring针对这些点继续发力,并且持续打造Dataflow套件,结合K8S打造成一个微服务的OS(各种中间件可以实现一键部署集群)。另外对于Spring Cloud除了核心功能之外,希望在管理台方面可以继续完善,打造一个一体化(不一定是一个网站,但是至少可以有权限控制和审计,实现SSO)的管理台,全面实现微服务部署伸缩、服务治理、数据流程管理、服务全链路监控、配置管理等等功能,也期待Spring Cloud和Dataflow双剑合璧在将来的2到3年定义微服务和以数据为核心的流处理的架构标准。

    展开全文
  • P89LPC932的几种ISP编程方法 作 者: 中国电子科技集团公司 陈凯 吴锦虹 覃波 引 言:  LPC900系列Flash单片机提供从8脚到28脚的封装形式,可以满足各种对成本和电路板空间限制而又要求高性能、高可靠性的...
  • Spring家族几大插件

    千次阅读 2018-11-29 13:05:15
     Spring家族很庞大,从最早先出现的服务于企业级程序开发的Core、安全方面的Security、到后来的作为各种数据源桥梁的Data、最近年很火的Boot,以及最新推出的正在蓬勃发展的Cloud(在本文之后都简单称为Boot、...

     

          Spring家族很庞大,从最早先出现的服务于企业级程序开发的Core、安全方面的Security、到后来的作为各种数据源桥梁的Data、最近几年很火的Boot,以及最新推出的正在蓬勃发展的Cloud(在本文之后都简单称为Boot、Cloud省略Spring节省一点我的打字时间?)。

          上面这个脑图给出了Spring家族主要的一些成员,右侧非Cloud部分列的是功能,左侧Cloud部分虽然组件繁杂,但是结构清晰(确实新版本清晰多了,命名也统一,你可以放大图片看一下这些是否熟悉),所以更进一步列出了组件要的一些模块依赖和开启功能的主注解。

    0.Spring的发展

    Spring框架几乎涉及到了Java企业级服务开发的所有方面,也几乎针对所有开发常用的模式、中间件、数据库进行了整合适配。

    之前在聊互联网架构模式的时候我谈到过,很多时候我们写一个业务把逻辑写死写出来是比较容易的,但是把这个逻辑提取成模式进而打包成一个框架来给大家使用,这是比较难的。因为我们只有经历过足够多的场景后才能提取出普适的功能框架,大部分人才能用上,而且我们需要针对核心功能开放出可配置的部分,满足小部分人进一步定制和扩展功能的需要。

    Spring框架经历了几个阶段:

    1.第一个阶段推出的Core、Security、Data是把单体应用开发服务好。不仅仅提供了便捷的数据库访问、Web MVC等必要功能,而且通过AOP、IOC两大利器让我们的程序内在能够做到低耦合可扩展。

    2.第二个阶段推出的Boot的意义不仅仅是加速了开发效率而且能让我们的程序从可用变为好用,应用程序核心业务逻辑可能只有70%的工作量,要让程序在线上跑的愉快还有30%的监控日志打点等工作量需要去做。

    3.第三个阶段推出的Cloud的意义在于推动了微服务架构的落地。让不具备开发微服务基础套件的小型互联网公司也能享受到免费的开箱即用的微服务解决方案。其实很多人不是看了微服务的架构思想去寻找解决方案,而是了解到了Spring Cloud才去了解微服务思想从而落地的。

    4.目前属于第四个阶段,大力发展Cloud Dataflow+容器。Dataflow的思想是不管是做实时消息处理的服务还是临时运行的任务,都可以认为是服务的组件,如果可以有一套DSL来定义这些组件之间的交互方式,然后在容器中进行自由组合、部署、伸缩,那么架构会非常灵活。下图是Dataflow管理界面的一个示意图。

          Spring的发展可以看到互联网架构的发展,Spring给我们带来相当多的技术启发,从软件设计模式的启发慢慢到了架构的启发,甚至我觉得Spring是为Java开发打造了架构风格的模板,接下去Spring继续发展2到3年有望成为架构标准,我在想这个时候应用架构师何去何从?

    1.Spring Core

            Spring Core提供的IOC、AOP功能已经变为半个Java命根子了。其实很多开发平台并不是那么强调IOC和AOP,甚至有的平台完全没有相关支持。虽然我一直觉得IOC和AOP是非常好的思想,可以让我们的软件内部做到组件之间的低耦合,容易替换,容易扩展,但是我的观点是,作为一个类库不应该把自己组件的初始化以及组装工作交给外部来做。我们知道通过IOC容器来管理我们组件的实例化和依赖,其实我们可以在程序内部实现每一个组件,把装配工作交给XML配置进行,但是对于一些复杂的组件,如果这个工作的配置交给XML进行,那么也就相当于交给了使用者进行,相当于需要使用者一定要理解组件内部的装配结构,这是不合理的。更合理的方式是,组件或框架的作者提供一些扩展点,让使用者可以明确通过API来注入自己的扩展组件或实现组件,而对于只需要简单使用组件的使用者可以无需配置开箱即用。

            当然,这不是说Spring的IOC和AOP有什么不好,正因为框架实现的如此灵活,Java使用Spring作为容器也基本是标准了,所以Java界很多框架也因此可以相互进行很好的集成,确实是一个很好的平台。

            Spring 5推出了Reactive非阻塞技术栈,基于Netty或Servlet 3.1+容器,提供了Stream API、WebFlux以及各种响应式的存储(各种NOSQL)访问类库。从前到后实现非阻塞的服务,可以避免IO阻塞占据线程,减少线程切换和资源使用,以最小的资源做到最大化的并发。可惜的是JDBC目前并没有非阻塞的版本,这样我们主流的基于MySQL的应用并不能进行全链路(从Controller到外部的Rest服务到数据库)的非阻塞IO(一竿子到底这样才是最爽的)。而且对于Reactive套件,我经过简单的使用个人感觉API比较晦涩,链式调用可读性并不高,而且反而遇到了并发的一些坑,加上代码的示例和最佳实践现在也很少,我感到现在使用并不是特别成熟。

    2.Spring Data

           Spring Data希望以相对比较一致的Template API来让我们更方便得使用各种数据存储。我个人不太喜欢习惯使用Data套件而是更喜欢使用各种NOSQL的Java原生客户端。几个原因:

    1.原生客户端紧跟服务端的实现,可以第一时间体验到最新的功能

    2.原生客户端的API和服务端提供的API往往一一匹配,可以一竿子到底,让我们功能使用更准确

    3.原生客户端往往只是基于API的简单封装,性能更好

           当然,如果我们只是对NOSQL进行简单使用的话,Spring Data可能使用起来更方便。

    3.Spring Boot

           稍微老一点的Java开发基本都是从纯XML配置到XML+注解配置走过来的,比较有意思的是很多开发虽然当初在使用XML配置,但是往往问他们每一个配置的含义都不能准确回答出,基本就是拿着主管或前人搭建的一套XML配置直接复制粘贴过来使用。从侧面说明了,其实我们大部分那些Mybatis、Spring MVC的配置都是在干组件初始化而不是定制化的事情。从0开始要让一个组件用起来就需要这些基本的配置,既然是这样的话,其实完全可以有默认配置,采用约定大于配置的方式来做。只有在我们需要针对组件进行定制化的时候才去做更多配置。

           Spring Boot不但在自动配置、配置简化上做了很多工作,而且还提供了轻量的嵌入式的容器,只需要20行的Pom+10行代码,就可以立即实现一个可以自启的应用程序(部署简单)激发了我们使用微服务的热情。此外也给我们做了很多Production-ready的启示(Actuator),告诉我们一个完善的应用程序应当注重环境切换、监控、日志、打点等等方面。总之,之前我们可能需要半天时间搭建一个项目,现在通过start.spring.io甚至只需要10秒。在有Boot之前,我实在没有兴趣使用重量级的Java(可能就为了访问下数据库做一些处理,还是使用Python算了)来创建一个实验性的控制台应用程序。

    4.Spring Cloud

     

          上图来自官网首页,很好地阐述了各个组件之间的关系。我们来逐一过一下脑图上的那些组件:

          1.配置管理Cloud Config:提供了客户端和服务端,客户端的使用方式和Spring完美结合,服务端提供了Git方式和文件方式的数据存储,最新版本也提供了数据库方式。这个配置管理的功能上和之前《朱晔的互联网架构实践心得S1E5:不断耕耘的基础中间件》一文中我探到的那些配置管理的功能差十万八千里。

           2.服务发现Netflix Euerka:提供可客户端和服务端(兼管理台),这里的客户端是指服务发现的使用方,其实微服务中的服务在这里是客户端。

           3.断路器Netflix Hustrix:提供了客户端API、聚合服务端Tubine和Dashboard网站。

           4.服务网关:有Netflix Zuul和Cloud Gateway两种网关可以选择,后者据说性能更好。网关其实就是典型的Filter+Handler的实现机制,通过路由找到合适的Handler,然后调用Pre和Post的各种插件式Filter。

           5.调用链跟踪Cloud Sleuth:可以搭配Zipkin使用,功能只能说凑活用。Zipkin的那后台功能上和国内主流互联网实现的Trace后台功能相比还是太弱了。

           6.消息驱动Cloud Stream:抽象成为了产出消息的Source,消费数据的Sink和抓换数据的Processor。然后把Broker的实现通过Binder进行解耦,支持主流的Kafka、KafkaStream和RabbitMQ三种类型。

           7.消息总线Cloud Bus:抽象了MQ的功能,支持主流的MQ产品。

           8.函数即服务Cloud Function:把函数封装为Web服务或Stream服务可以独立调用。对函数编程的Function、Consumer和Supplier分别映射成为了Processor、Sink和Source。

            9.微服务契约Cloud Contract:实现契约优先的编程,可以先定义契约对契约进行测试,同时进行服务实现。复杂的服务可以用这套方式来做,消费者提供者对着契约自己编自己的,两不耽误。

           10.任务框架Cloud Task:非定时任务的概念,这里的任务是指一次性运行的进程。框架提供了任务执行审计管理最基本的功能。这里的任务最后可以在Cloud Dataflow中运行也可以独立运行。

            11.管理台:这里列的Admin管理台是第三方提供的,基于Actuator的端点进行信息的综合展示和监控。

            总结一下,总体上我感觉Cloud模块化的思想很好,模块和模块之间可以相互搭配使用,但是可能一开始没有进行系统性的规划,版本的升级带来的Breaking Changes有点过多,而且因为内容太多了,文档方面没有特别全面,要全部用起来坑会比较多,需要享受新功能的话还需要不断更新框架版本不断踩坑。

            从目前功能的完善程度来说我感觉核心功能完善度在60%(大概还需要发展1年可以用的比较舒服)。后台方面过于简陋,官方提供的后台零散丑陋而且完成度极低(相比国内一线互联网在治理这块开发的功能来说,完善度大概在30%,大概还需要发展2年可以用的比较舒服,如果可以好好规划一套完整的后台把服务治理所有相关功能都整合在一起就好了)。不管怎么样,至少Cloud套件是一套完整的解决方案,目前来看还没有可以媲美的其它开源选择可以使用(Dubbo我们也知道虽然现在又开始高速迭代,但是由于其原始定位是RPC框架,理念上还是有很多不同的,组件方面并没有Cloud那么完善)。

            除了功能不完善,Cloud令我担心的还有一点是(我没测试过,但是因为看到目前功能的迭代速度对这方面信心不足,谁大规模应用了能否可以给点数据),这些中间件(服务发现、网关服务、链路跟踪、配置管理)是不是经过压测,是否可以满足比较大的压力,如果只是实现功能的话,可能会在全面用起来后遇到性能瓶颈,在这个时候恐怕就麻烦了。

    总结

            Spring家族已经是功能强大的庞然大物了,我们的项目pom中出现几十个Spring依赖也是家常便饭。使用.NET家族的套件也是几年前的事情了,但是至今我还是觉得微软.NET的开发套件不管是MVC还是ORM还是RPC方面比Spring的MVC、Data JPA(现在大家都使用Mybatis,Mybatis也还是太弱了)、Cloud套件在功能和设计的优雅上更胜一筹,希望将来可以看到Spring针对这些点继续发力,并且持续打造Dataflow套件,结合K8S打造成一个微服务的OS(各种中间件可以实现一键部署集群)。另外对于Spring Cloud除了核心功能之外,希望在管理台方面可以继续完善,打造一个一体化(不一定是一个网站,但是至少可以有权限控制和审计,实现SSO)的管理台,全面实现微服务部署伸缩、服务治理、数据流程管理、服务全链路监控、配置管理等等功能,也期待Spring Cloud和Dataflow双剑合璧在将来的2到3年定义微服务和以数据为核心的流处理的架构标准。

    展开全文
  • 几种常用的设计模式介绍

    万次阅读 多人点赞 2013-11-16 18:17:27
    几种常用的设计模式介绍 1.  设计模式的起源 最早提出“设计模式”概念的是建筑设计大师亚力山大Alexander。在1970年他的《建筑的永恒之道》里描述了投计模式的发现,因为它已经存在了千百年之久,而现代才被...

     

    几种常用的设计模式介绍

    1.    设计模式的起源

    最早提出“设计模式”概念的是建筑设计大师亚力山大Alexander。在1970他的《建筑的永恒之道》里描述了投计模式的发现,因为它已经存在了千百年之久,而现代才被通过大量的研究而被发现。

    在《建筑的永恒之道》里这样描述:模式是一条由三个部分组成的通用规则:它表示了一个特定环境一类问题一个解决方案之间的关系。每一个模式描述了一个不断重复发生的问题,以及该问题解决方案的核心设计

     

    在他的另一本书《建筑模式语言》中提到了现在已经定义了253种模式。比如:

    说明城市主要的结构:亚文化区的镶嵌、分散的工作点、城市的魅力、地方交通区

    住宅团组:户型混合、公共性的程度、住宅团组、联排式住宅、丘状住宅、老人天地室内环境和室外环境、阴和阳总是一气呵成

    针对住宅:夫妻的领域、儿童的领域、朝东的卧室、农家的厨房、私家的沿街露台、个人居室、起居空间的序列、多床卧室、浴室、大储藏室

    针对办公室、车间和公共建筑物:灵活办公空间、共同进餐、共同小组、宾至如归、等候场所、小会议室、半私密办公室

     

    尽管亚力山大的著作是针对建筑领域的,但他的观点实际上适用于所有的工程设计领域,其中也包括软件设计领域。“软件设计模式”,这个术语是在1990年代由Erich Gamma等人从建筑设计领域引入到计算机科学中来的。目前主要有23种。

     

    2.    软件设计模式的分类

    2.1.  创建型

    创建对象时,不再由我们直接实例化对象;而是根据特定场景,由程序来确定创建对象的方式,从而保证更大的性能、更好的架构优势。创建型模式主要有简单工厂模式(并不是23种设计模式之一)、工厂方法、抽象工厂模式单例模式、生成器模式和原型模式

    2.2.  结构型

    用于帮助将多个对象组织成更大的结构。结构型模式主要有适配器模式adapter桥接模式bridge、组合器模式component、装饰器模式decorator门面模式、亨元模式flyweight代理模式proxy

    2.3.  行为型

    用于帮助系统间各对象的通信,以及如何控制复杂系统中流程。行为型模式主要有命令模式command、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式state策略模式、模板模式和访问者模式

    3.    常见设计模式介绍

    3.1.  单例模式(singleton)

    有些时候,允许自由创建某个类的实例没有意义,还可能造成系统性能下降。如果一个类始终只能创建一个实例,则这个类被称为单例类,这种模式就被称为单例模式。

        一般建议单例模式的方法命名为:getInstance(),这个方法的返回类型肯定是单例类的类型了。getInstance方法可以有参数,这些参数可能是创建类实例所需要的参数,当然,大多数情况下是不需要的

    publicclass Singleton {

       

        publicstaticvoid main(String[] args)

        {

           //创建Singleton对象不能通过构造器,只能通过getInstance方法

           Singleton s1 = Singleton.getInstance();

           Singleton s2 = Singleton.getInstance();

           //将输出true

           System.out.println(s1 == s2);

        }

       

        //使用一个变量来缓存曾经创建的实例

        privatestatic Singleton instance;

        //将构造器使用private修饰,隐藏该构造器

        private Singleton(){

           System.out.println("Singleton被构造!");

        }

       

        //提供一个静态方法,用于返回Singleton实例

        //该方法可以加入自定义的控制,保证只产生一个Singleton对象

        publicstatic Singleton getInstance()

        {

           //如果instancenull,表明还不曾创建Singleton对象

           //如果instance不为null,则表明已经创建了Singleton对象,将不会执行该方法

           if (instance == null)

           {

               //创建一个Singleton对象,并将其缓存起来

               instance = new Singleton();

           }

           returninstance;

        }

    }

    单例模式主要有如下两个优势:

    1)      减少创建Java实例所带来的系统开销

    2)      便于系统跟踪单个Java实例的生命周期、实例状态等。

     

    3.2.  简单工厂(StaticFactory Method)

    简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

    A实例调用B实例的方法,称为A依赖于B。如果使用new关键字来创建一个B实例(硬编码耦合),然后调用B实例的方法。一旦系统需要重构:需要使用C类来代替B类时,程序不得不改写A类代码。而用工厂模式则不需要关心B对象的实现、创建过程。

    Output,接口

    publicinterface Output

    {

        //接口里定义的属性只能是常量

        intMAX_CACHE_LINE = 50;

        //接口里定义的只能是public的抽象实例方法

        void out();

        void getData(String msg);

    }

    PrinterOutput的一个实现

    //Printer类实现Output

    publicclass Printer implements Output

    {

        private String[] printData = new String[MAX_CACHE_LINE];

        //用以记录当前需打印的作业数

        privateintdataNum = 0;

        publicvoid out()

        {

           //只要还有作业,继续打印

           while(dataNum > 0)

           {

               System.out.println("打印机打印:" + printData[0]);

               //把作业队列整体前移一位,并将剩下的作业数减1

               System.arraycopy(printData , 1, printData, 0, --dataNum);

           }

        }

        publicvoid getData(String msg)

        {

           if (dataNum >= MAX_CACHE_LINE)

           {

               System.out.println("输出队列已满,添加失败");

           }

           else

           {

               //把打印数据添加到队列里,已保存数据的数量加1

               printData[dataNum++] = msg;

           }

        }

    }

    BetterPrinterOutput的一个实现

    publicclass BetterPrinter implements Output

    {

        private String[] printData = new String[MAX_CACHE_LINE * 2];

        //用以记录当前需打印的作业数

        privateintdataNum = 0;

        publicvoid out()

        {

           //只要还有作业,继续打印

           while(dataNum > 0)

           {

               System.out.println("高速打印机正在打印:" + printData[0]);

               //把作业队列整体前移一位,并将剩下的作业数减1

               System.arraycopy(printData , 1, printData, 0, --dataNum);

           }

        }

        publicvoid getData(String msg)

        {

           if (dataNum >= MAX_CACHE_LINE * 2)

           {

               System.out.println("输出队列已满,添加失败");

           }

           else

           {

               //把打印数据添加到队列里,已保存数据的数量加1

               printData[dataNum++] = msg;

           }

        }

    }

    OutputFactory,简单工厂类

        public Output getPrinterOutput(String type) {

           if (type.equalsIgnoreCase("better")) {

               returnnew BetterPrinter();

           } else {

               returnnew Printer();

           }

        }

    Computer

    publicclass Computer

    {

        private Output out;

     

        public Computer(Output out)

        {

           this.out = out;

        }

        //定义一个模拟获取字符串输入的方法

        publicvoid keyIn(String msg)

        {

           out.getData(msg);

        }

        //定义一个模拟打印的方法

        publicvoid print()

        {

           out.out();

        }

        publicstaticvoid main(String[] args)

        {

           //创建OutputFactory

           OutputFactory of = new OutputFactory();

           //Output对象传入,创建Computer对象

           Computer c = new Computer(of.getPrinterOutput("normal"));

           c.keyIn("建筑永恒之道");

           c.keyIn("建筑模式语言");

           c.print();

          

     

           c = new Computer(of.getPrinterOutput("better"));

           c.keyIn("建筑永恒之道");

           c.keyIn("建筑模式语言");

           c.print();

        }

     

    使用简单工厂模式的优势:让对象的调用者和对象创建过程分离,当对象调用者需要对象时,直接向工厂请求即可。从而避免了对象的调用者与对象的实现类以硬编码方式耦合,以提高系统的可维护性、可扩展性。工厂模式也有一个小小的缺陷:当产品修改时,工厂类也要做相应的修改。

    3.3.  工厂方法(Factory Method)和抽象工厂(Abstract Factory)

    如果我们不想在工厂类中进行逻辑判断,程序可以为不同产品类提供不同的工厂,不同的工厂类和产不同的产品。

    当使用工厂方法设计模式时,对象调用者需要与具体的工厂类耦合,如:

    //工厂类的定义1

    publicclass BetterPrinterFactory

        implements OutputFactory

    {

        public Output getOutput()

        {

           //该工厂只负责产生BetterPrinter对象

           returnnew BetterPrinter();

        }

    }

    //工厂类的定义2

    publicclass PrinterFactory

        implements OutputFactory

    {

        public Output getOutput()

        {

           //该工厂只负责产生Printer对象

           returnnew Printer();

        }

    }

    //工厂类的调用

    //OutputFactory of = new BetterPrinterFactory();

    OutputFactory of = new PrinterFactory();

    Computer c = new Computer(of.getOutput());

     

    使用简单工厂类,需要在工厂类里做逻辑判断。而工厂类虽然不用在工厂类做判断。但是带来了另一种耦合:客户端代码与不同的工厂类耦合。

     

    为了解决客户端代码与不同工厂类耦合的问题。在工厂类的基础上再增加一个工厂类,该工厂类不制造具体的被调用对象,而是制造不同工厂对象。如:

    //抽象工厂类的定义,在工厂类的基础上再建一个工厂类

    publicclass OutputFactoryFactory

    {

        //仅定义一个方法用于返回输出设备。

        publicstatic OutputFactory getOutputFactory(

           String type)

        {

           if (type.equalsIgnoreCase("better"))

           {

               returnnew BetterPrinterFactory();

           }

           else

           {

               returnnew PrinterFactory();

           }

        }

    }

     

    //抽象工厂类的调用

    OutputFactory of = OutputFactoryFactory.getOutputFactory("better");

    Computer c = new Computer(of.getOutput());

     

    3.4.  代理模式(Proxy)

    代理模式是一种应用非常广泛的设计模式,当客户端代码需要调用某个对象时,客户端实际上不关心是否准确得到该对象,它只要一个能提供该功能的对象即可,此时我们就可返回该对象的代理(Proxy)。

    代理就是一个Java对象代表另一个Java对象来采取行动。如:

    publicclass ImageProxy implements Image

    {

        //组合一个image实例,作为被代理的对象

        private Image image;

        //使用抽象实体来初始化代理对象

        public ImageProxy(Image image)

        {

           this.image = image;

        }

        /**

         * 重写Image接口的show()方法

         * 该方法用于控制对被代理对象的访问,

         * 并根据需要负责创建和删除被代理对象

         */

        publicvoid show()

        {

           //只有当真正需要调用imageshow方法时才创建被代理对象

           if (image == null)

           {

               image = new BigImage();

           }

           image.show();

        }

    }

    调用时,先不创建:

    Image image = new ImageProxy(null);

     

    Hibernate默认启用延迟加载,当系统加载A实体时,A实体关联的B实体并未被加载出来,A实体所关联的B实体全部是代理对象——只有等到A实体真正需要访问B实体时,系统才会去数据库里抓取B实体所对应的记录。

    借助于Java提供的ProxyInvocationHandler,可以实现在运行时生成动态代理的功能,而动态代理对象就可以作为目标对象使用,而且增强了目标对象的功能。如:

    Panther

    publicinterface Panther

    {

        //info方法声明

        publicvoid info();

        //run方法声明

        publicvoid run();

    }

    GunPanther

    publicclass GunPanther implements Panther

    {

        //info方法实现,仅仅打印一个字符串

        publicvoid info()

        {

           System.out.println("我是一只猎豹!");

        }

        //run方法实现,仅仅打印一个字符串

        publicvoid run()

        {

           System.out.println("我奔跑迅速");

        }

    }

    MyProxyFactory,创建代理对象

    publicclass MyProxyFactory

    {

        //为指定target生成动态代理对象

        publicstatic Object getProxy(Object target)

           throws Exception

        {

           //创建一个MyInvokationHandler对象

           MyInvokationHandler handler =

               new MyInvokationHandler();

           //MyInvokationHandler设置target对象

           handler.setTarget(target);

           //创建、并返回一个动态代理

           return Proxy.newProxyInstance(target.getClass().getClassLoader()

               , target.getClass().getInterfaces(), handler);

        }

    }

    MyInvokationHandler,增强代理的功能

    publicclass MyInvokationHandler implements InvocationHandler

    {

        //需要被代理的对象

        private Object target;

        publicvoid setTarget(Object target)

        {

           this.target = target;

        }

        //执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法

        public Object invoke(Object proxy, Method method, Object[] args)

           throws Exception

        {

           TxUtil tx = new TxUtil();

           //执行TxUtil对象中的beginTx

           tx.beginTx();

           //target作为主调来执行method方法

           Object result = method.invoke(target , args);

           //执行TxUtil对象中的endTx

           tx.endTx();

           return result;

        }

    }

    TxUtil

    publicclass TxUtil

    {

        //第一个拦截器方法:模拟事务开始

        publicvoid beginTx()

        {

           System.out.println("=====模拟开始事务=====");

        }

        //第二个拦截器方法:模拟事务结束

        publicvoid endTx()

        {

           System.out.println("=====模拟结束事务=====");

        }

    }

    测试

        publicstaticvoid main(String[] args)

           throws Exception

        {

           //创建一个原始的GunDog对象,作为target

           Panther target = new GunPanther();

           //以指定的target来创建动态代理

           Panther panther = (Panther)MyProxyFactory.getProxy(target);

           //调用代理对象的info()run()方法

           panther.info();

           panther.run();

        }

    Spring所创建的AOP代理就是这种动态代理。但是Spring AOP更灵活。

    3.5.  命令模式(Command)

    某个方法需要完成某一个功能,完成这个功能的大部分步骤已经确定了,但可能有少量具体步骤无法确定,必须等到执行该方法时才可以确定。(在某些编程语言如RubyPerl里,允许传入一个代码块作为参数。但Jara暂时还不支持代码块作为参数)。在Java中,传入该方法的是一个对象,该对象通常是某个接口的匿名实现类的实例,该接口通常被称为命令接口,这种设计方式也被称为命令模式。

    如:

    Command

    publicinterface Command

    {

        //接口里定义的process方法用于封装处理行为

        void process(int[] target);

    }

    ProcessArray

    publicclass ProcessArray

    {

        //定义一个each()方法,用于处理数组,

        publicvoid each(int[] target , Command cmd)

        {

           cmd.process(target);

        }

    }

    TestCommand

    publicclass TestCommand

    {

        publicstaticvoid main(String[] args)

        {

           ProcessArray pa = new ProcessArray();

           int[] target = {3, -4, 6, 4};

           //第一次处理数组,具体处理行为取决于Command对象

           pa.each(target , new Command()

           {

               //重写process()方法,决定具体的处理行为

               publicvoid process(int[] target)

               {

                  for (int tmp : target )

                  {

                      System.out.println("迭代输出目标数组的元素:" + tmp);

                  }

               }

           });

           System.out.println("------------------");

           //第二次处理数组,具体处理行为取决于Command对象

           pa.each(target , new Command()

           {

               //重写process方法,决定具体的处理行为

               publicvoid process(int[] target)

               {

                  int sum = 0;

                  for (int tmp : target )

                  {

                      sum += tmp;         

                  }

                  System.out.println("数组元素的总和是:" + sum);

               }

           });

        }

    }

     

    HibernateTemplate使用了executeXxx()方法弥补了HibernateTemplate的不足,该方法需要接受一个HibernateCallback接口,该接口的代码如下:

    public interface HibernateCallback

    {

           Object doInHibernate(Session session);

    }

     

    3.6.  策略模式(Strategy)

    策略模式用于封装系列的算法,这些算法通常被封装在一个被称为Context的类中,客户端程序可以自由选择其中一种算法,或让Context为客户端选择一种最佳算法——使用策略模式的优势是为了支持算法的自由切换。

    DiscountStrategy,折扣方法接口

    publicinterface DiscountStrategy

    {

        //定义一个用于计算打折价的方法

        double getDiscount(double originPrice);

    }

    OldDiscount,旧书打折算法

    publicclass OldDiscount implements DiscountStrategy {

        // 重写getDiscount()方法,提供旧书打折算法

        publicdouble getDiscount(double originPrice) {

           System.out.println("使用旧书折扣...");

           return originPrice * 0.7;

        }

    }

    VipDiscountVIP打折算法

    //实现DiscountStrategy接口,实现对VIP打折的算法

    publicclass VipDiscount implements DiscountStrategy {

        // 重写getDiscount()方法,提供VIP打折算法

        publicdouble getDiscount(double originPrice) {

           System.out.println("使用VIP折扣...");

           return originPrice * 0.5;

        }

    }

    策略定义

    publicclass DiscountContext

    {

        //组合一个DiscountStrategy对象

        private DiscountStrategy strategy;

        //构造器,传入一个DiscountStrategy对象

        public DiscountContext(DiscountStrategy strategy)

        {

           this.strategy  = strategy;

        }

        //根据实际所使用的DiscountStrategy对象得到折扣价

        publicdouble getDiscountPrice(double price)

        {

           //如果strategynull,系统自动选择OldDiscount

           if (strategy == null)

           {

               strategy = new OldDiscount();

           }

           returnthis.strategy.getDiscount(price);

        }

        //提供切换算法的方法

        publicvoid setDiscount(DiscountStrategy strategy)

        {

           this.strategy = strategy;

        }

    }

    测试

        publicstaticvoid main(String[] args)

        {

           //客户端没有选择打折策略类

           DiscountContext dc = new DiscountContext(null);

           double price1 = 79;

           //使用默认的打折策略

           System.out.println("79元的书默认打折后的价格是:"

               + dc.getDiscountPrice(price1));

           //客户端选择合适的VIP打折策略

           dc.setDiscount(new VipDiscount());

           double price2 = 89;

           //使用VIP打折得到打折价格

           System.out.println("89元的书对VIP用户的价格是:"

               + dc.getDiscountPrice(price2));

        }

    使用策略模式可以让客户端代码在不同的打折策略之间切换,但也有一个小小的遗憾:客户端代码需要和不同的策略耦合。为了弥补这个不足,我们可以考虑使用配置文件来指定DiscountContext使用哪种打折策略——这就彻底分离客户端代码和具体打折策略类。

    3.7.  门面模式(Facade)

    随着系统的不断改进和开发,它们会变得越来越复杂,系统会生成大量的类,这使得程序流程更难被理解。门面模式可为这些类提供一个简化的接口,从而简化访问这些类的复杂性。

           门面模式(Facade)也被称为正面模式、外观模式,这种模式用于将一组复杂的类包装到一个简单的外部接口中。

     

    原来的方式

           // 依次创建三个部门实例

           Payment pay = new PaymentImpl();

           Cook cook = new CookImpl();

           Waiter waiter = new WaiterImpl();

           // 依次调用三个部门实例的方法来实现用餐功能

           String food = pay.pay();

           food = cook.cook(food);

           waiter.serve(food);

    门面模式

    publicclass Facade {

        // 定义被Facade封装的三个部门

        Payment pay;

        Cook cook;

        Waiter waiter;

     

        // 构造器

        public Facade() {

           this.pay = new PaymentImpl();

           this.cook = new CookImpl();

           this.waiter = new WaiterImpl();

        }

     

        publicvoid serveFood() {

           // 依次调用三个部门的方法,封装成一个serveFood()方法

           String food = pay.pay();

           food = cook.cook(food);

           waiter.serve(food);

        }

    }

    门面模式调用

           Facade f = new Facade();

           f.serveFood();

    3.8.  桥接模式(Bridge)

    由于实际的需要,某个类具有两个以上的维度变化,如果只是使用继承将无法实现这种需要,或者使得设计变得相当臃肿。而桥接模式的做法是把变化部分抽象出来,使变化部分与主类分离开来,从而将多个的变化彻底分离。最后提供一个管理类来组合不同维度上的变化,通过这种组合来满足业务的需要。

    Peppery口味风格接口:

    publicinterface Peppery

    {

        String style();

    }

    口味之一

    publicclass PepperySytle implements Peppery

    {

        //实现"辣味"风格的方法

        public String style()

        {

           return"辣味很重,很过瘾...";

        }

    }

    口味之二

    publicclass PlainStyle implements Peppery

    {

        //实现"不辣"风格的方法

        public String style()

        {

           return"味道清淡,很养胃...";

        }

    }

    口味的桥梁

    publicabstractclass AbstractNoodle

    {

        //组合一个Peppery变量,用于将该维度的变化独立出来

        protected Peppery style;

        //每份Noodle必须组合一个Peppery对象

        public AbstractNoodle(Peppery style)

        {

           this.style = style;

        }

        publicabstractvoid eat();

    }

    材料之一,继承口味

    publicclass PorkyNoodle extends AbstractNoodle

    {

        public PorkyNoodle(Peppery style)

        {

           super(style);

        }

        //实现eat()抽象方法

        publicvoid eat()

        {

           System.out.println("这是一碗稍嫌油腻的猪肉面条。"

               + super.style.style());

        }

    }

    材料之二,继承口味

    publicclass BeefMoodle extends AbstractNoodle

    {

        public BeefMoodle(Peppery style)

        {

           super(style);

        }

        //实现eat()抽象方法

        publicvoid eat()

        {

           System.out.println("这是一碗美味的牛肉面条。"

               + super.style.style());

        }

    }

    主程序

    publicclass Test

    {

        publicstaticvoid main(String[] args)

        {

           //下面将得到辣味的牛肉面

           AbstractNoodle noodle1 = new BeefMoodle(

               new PepperySytle());

           noodle1.eat();

           //下面将得到不辣的牛肉面

           AbstractNoodle noodle2 = new BeefMoodle(

               new PlainStyle());

           noodle2.eat();

           //下面将得到辣味的猪肉面

           AbstractNoodle noodle3 = new PorkyNoodle(

               new PepperySytle());

           noodle3.eat();

           //下面将得到不辣的猪肉面

           AbstractNoodle noodle4 = new PorkyNoodle(

               new PlainStyle());

           noodle4.eat();

        }

    }

    Java EE应用中常见的DAO模式正是桥接模式的应用。

    实际上,一个设计优良的项目,本身就是设计模式最好的教科书,例如Spring框架,当你深入阅读其源代码时,你会发现这个框架处处充满了设计模式的应用场景。

    http://www.cnblogs.com/liuling/archive/2013/04/20/observer.html

    3.9.  观察者模式(Observer)

     观察者模式结构中包括四种角色:

      一、主题:主题是一个接口,该接口规定了具体主题需要实现的方法,比如添加、删除观察者以及通知观察者更新数据的方法。

      二、观察者:观察者也是一个接口,该接口规定了具体观察者用来更新数据的方法。

      三、具体主题:具体主题是一个实现主题接口的类,该类包含了会经常发生变化的数据。而且还有一个集合,该集合存放的是观察者的引用。

      四:具体观察者:具体观察者是实现了观察者接口的一个类。具体观察者包含有可以存放具体主题引用的主题接口变量,以便具体观察者让具体主题将自己的引用添加到具体主题的集合中,让自己成为它的观察者,或者让这个具体主题将自己从具体主题的集合中删除,使自己不在时它的观察者。

     

    观察者模式定义了对象间的一对多依赖关系,让一个或多个观察者对象观察一个主题对象。当主题对象的状态发生变化时,系统能通知所有的依赖于此对象的观察者对象,从而使得观察者对象能够自动更新。

    在观察者模式中,被观察的对象常常也被称为目标或主题(Subject),依赖的对象被称为观察者(Observer)。

    Observer观察者接口:

    观察者:观察者也是一个接口,该接口规定了具体观察者用来更新数据的方法

    publicinterface Observer {

        void update(Observable o, Object arg);

    }

    Observable目标或主题:

    主题:主题是一个接口,该接口规定了具体主题需要实现的方法,比如添加、删除观察者以及通知观察者更新数据的方法

    import java.util.ArrayList;

    import java.util.List;

    import java.util.Iterator;

     

    publicabstractclass Observable {

        // 用一个List来保存该对象上所有绑定的事件监听器

        List<Observer> observers = new ArrayList<Observer>();

     

        // 定义一个方法,用于从该主题上注册观察者

        publicvoid registObserver(Observer o) {

           observers.add(o);

        }

     

        // 定义一个方法,用于从该主题中删除观察者

        publicvoid removeObserver(Observer o) {

           observers.add(o);

        }

     

        // 通知该主题上注册的所有观察者

        publicvoid notifyObservers(Object value) {

           // 遍历注册到该被观察者上的所有观察者

           for (Iterator it = observers.iterator(); it.hasNext();) {

               Observer o = (Observer) it.next();

               // 显式每个观察者的update方法

               o.update(this, value);

           }

        }

    }

    Product被观察类

    具体主题:具体主题是一个实现主题接口的类,该类包含了会经常发生变化的数据。而且还有一个集合,该集合存放的是观察者的引用。

    publicclass Product extends Observable {

        // 定义两个属性

        private String name;

        privatedoubleprice;

     

        // 无参数的构造器

        public Product() {

        }

     

        public Product(String name, double price) {

           this.name = name;

           this.price = price;

        }

     

        public String getName() {

           returnname;

        }

     

        // 当程序调用namesetter方法来修改Productname属性时

        // 程序自然触发该对象上注册的所有观察者

        publicvoid setName(String name) {

           this.name = name;

           notifyObservers(name);

        }

     

        publicdouble getPrice() {

           returnprice;

        }

     

        // 当程序调用pricesetter方法来修改Productprice属性时

        // 程序自然触发该对象上注册的所有观察者

        publicvoid setPrice(double price) {

           this.price = price;

           notifyObservers(price);

        }

    }

     

    具体观察者:具体观察者是实现了观察者接口的一个类。具体观察者包含有可以存放具体主题引用的主题接口变量,以便具体观察者让具体主题将自己的引用添加到具体主题的集合中,让自己成为它的观察者,或者让这个具体主题将自己从具体主题的集合中删除,使自己不在时它的观察者。

     

    NameObserver名称观察者

    import javax.swing.JFrame;

    import javax.swing.JLabel;

     

    publicclass NameObserver implements Observer {

        // 实现观察者必须实现的update方法

        publicvoid update(Observable o, Object arg) {

           if (arg instanceof String) {

               // 产品名称改变值在name

               String name = (String) arg;

               // 启动一个JFrame窗口来显示被观察对象的状态改变

               JFrame f = new JFrame("观察者");

               JLabel l = new JLabel("名称改变为:" + name);

               f.add(l);

               f.pack();

               f.setVisible(true);

               System.out.println("名称观察者:" + o + "物品名称已经改变为: " + name);

           }

        }

    }

    PriceObserver价格观察者:

    publicclass PriceObserver implements Observer {

        // 实现观察者必须实现的update方法

        publicvoid update(Observable o, Object arg) {

           if (arg instanceof Double) {

               System.out.println("价格观察者:" + o + "物品价格已经改变为: " + arg);

           }

        }

    }

    测试:

    publicclass Test {

        publicstaticvoid main(String[] args) {

           // 创建一个被观察者对象

           Product p = new Product("电视机", 176);

           // 创建两个观察者对象

           NameObserver no = new NameObserver();

           PriceObserver po = new PriceObserver();

           // 向被观察对象上注册两个观察者对象

           p.registObserver(no);

           p.registObserver(po);

           // 程序调用setter方法来改变Productnameprice属性

           p.setName("书桌");

           p.setPrice(345f);

        }

    }

     

    其中Java工具类提供了被观察者抽象基类:java.util.Observable。观察者接口:java.util.Observer

     

    我们可以把观察者接口理解成事件监听接口,而被观察者对象也可当成事件源处理——换个角度来思考:监听,观察,这两个词语之间有本质的区别吗?Java事件机制的底层实现,本身就是通过观察者模式来实现的。除此之外,主题/订阅模式下的JMS本身就是观察者模式的应用。

     

     

    展开全文
  • 计算机网络几种常见协议

    万次阅读 多人点赞 2019-08-12 03:18:57
    一 .典型协议: 传输层: 常见的协议 TCP/UDP 协议 应用层: 常见的协议 HTTP,FTP 协议 网络层: 常见的协议 IP 协议,ICMP 协议,...TCP 传输控协议(TransmissionControl Protocol)是一面向连接的,...

    一 .典型协议:

    传输层: 常见的协议有 TCP/UDP 协议

    应用层: 常见的协议有 HTTP,FTP 协议

    网络层: 常见的协议有 IP 协议,ICMP 协议,IGMP 协议

    网络接口层: 常见的协议有 ARP 协议,RARP 协议

    TCP 传输控协议(TransmissionControl Protocol)是一种面向连接的,可靠的,基于字节流的传输层通信协议

    UDP 用户数据包协议(UserDatagram Protocol)是 OSI 参考模型中一种无连接的传输层协议,提供面向事物的简单不可靠信息传送服务

    HTTP 超文本传输系协议(HyperText Transfer Protocol)是互联网上应用最为广泛的一种协议

    FTP 文件传输协议(File Transfer Protocol)

    IP 协议是英特网互联协议(Internet Protocol)

    ICMP 协议是 Internet 控制报文协议(Internet Control Message Protocol),它是 TCP/IP 协议族的一个子协议,用于在 IP 主机、路由器之间传递控制消息

    IGMP 协议是 Internet 网际组管理协议,是英特网协议家族中的一个组播协议。该协议运行在主机和组播路由之间

    ARP 协议是正向地址解析协议(Address Resolution Protocol),通过已知的 IP,寻找对应主机的 MAC 地址

    RARP 协议是方向地址解析协议,通过 MAC 地址确定 IP地址

    TFTP 协议是 TCP/IP 协议族中的一个用来在客户机和服务器之间进行简单文件传输的协议,提供不复杂、开销不大 的文件传输协议

    DHCP 协议,动态主机配置协议,是一种让系统得以连接到网络上的,并获取 所需要的配置参数的手段

    NAT 协议,网络地址转换属接入广域网(WAN),是将一种私有(保留)地址转换为合法IP地址的转换技术

    二.TCP 和 UDP对应的协议

    TCP 对应的协议:

    (1)、FTP:定义了文件传输协议,使用 21 端口。

    (2)、Telnet:远程登录协议。使用 23 号端口,用户可以以自己的身份远程登录到计算机上,可提供基于DOS模式下的通信服务。

    (3)、SMTP:邮件传送协议,用于发送邮件。服务器开放的端口是 25 号端口。

    (4)、POP3 :它和 SMTP 对应,POP3用于接收协议。所用的端口是 110。

    (5)、HTTP:是从 Web 服务器传送超文本到本地浏览器的传送协议。

    UDP对应的协议:

    (1)、DNS:用于域名解析服务,将域名地址转换为 IP 地址。DNS 用的是 53号端口。

    (2)、SNMP:简单网络管理协议,使用 161 号端口,是用来管理网络设备。

    (3)、TFTP:简单文件传输协议,在 69 号端口上使用 UDP 服务。

    展开全文
  • 几种常见加密算法

    万次阅读 2019-06-27 09:36:02
    ,后一两位可能“=”,生成的编码都是ascii字符。 优点 :速度快,ascii字符,肉眼不可理解 缺点 :编码比较长,非常容易被破解,仅适用于 加密非关键信息 的场合   六、加密算法输出长度 算法 ...
  • 生成Json的几种方式

    千次阅读 2018-05-14 17:39:21
    SON(JavaScript Object Notation) 是一轻量级的数据交换格式,主要用于传送数据。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)...
  • python 几种常见的测试框架

    千次阅读 2018-08-07 20:05:16
    python 几种常见的测试框架 1. unittest 参考文档: https://docs.python.org/3/library/unittest.html unittest笔记 The unittest unit testing framework was originally inspired by JUnit and has a ...
  • 代码——几种常见的空格符号

    千次阅读 2020-12-22 19:07:46
    几种常见的空格符号 &nbsp; 半角的不断行的空白格(推荐使用) 它叫不换行空格,全称No-Break Space,它是最常见和我们使用最多的空格,大多数的人可能只接触了&nbsp;,它是按下space键产生的空格。 在...
  • C语言几种特殊的自定义类型

    万次阅读 2018-03-29 14:15:56
    C语言几种特殊的自定义类型 结构体 结构体的创建 可以在创建结构体的时候添加结构体的标签tag,用来为该结构体取唯一的名字,以便于和其它结构体区分开。 struct tag{ member_list; } variable_list; 也...
  • Android json数据的几种方法

    千次阅读 2018-06-08 09:21:03
    一、什么是json百度百科中对json的介绍是这样的:JSON(JavaScript Object Notation) 是一轻量级的数据交换格式。它基于JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一个子集。 JSON采用完全...
  • 常用几种消息摘要算法

    千次阅读 2019-10-24 11:57:01
    以下几种: 1、 MD5 (Message Digest algorithm 5 消息摘要算法版本5) MD是应用非常广泛的一个算法家族,尤其是 MD5(Message-Digest Algorithm 5,消息摘要算法版本5),它由MD2、MD3、MD4发展而来,由Ron ...
  • 几种常见的加密算法

    千次阅读 2020-01-13 14:43:39
    二、几种常见的加密算法  1、 Base64算法  原码 /** * Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一。 */ public class Base64Util { /* 我们知道Java中是用"8个二进制数字"表示一...
  • 计算机网络几种常见的协议

    万次阅读 多人点赞 2018-09-24 22:11:21
     传输层: 常见的协议 TCP/UDP 协议  应用层: 常见的协议 HTTP,FTP 协议  网络层: 常见的协议 IP 协议,ICMP 协议,IGMP 协议  网络接口层: 常见的协议 ARP 协议,RARP 协议 ...
  • Python几种比较常见的测试框架

    千次阅读 2017-07-18 17:27:54
    python 几种常见的测试框架 unittest 参考文档: https://docs.python.org/3/library/unittest.htmlunittest笔记The unittest unit testing framework was originally inspired by JUnit and has a similar flavor ...
  • C#解析JSON几种方式

    万次阅读 2013-06-22 23:15:47
    一、什么是JSON JSON(JavaScript Object Notation) 是一轻量级的数据交换格式。它基于JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了...
  • 几种常见web 容器比较

    万次阅读 2018-10-25 22:32:08
    如与上面提到的JBoss集成起来开发EJB,与Cocoon(Apache的另外一个项目)集成起来开发基于Xml的应用,与OpenJMS集成起来开发JMS应用,除了我们提到的这几种,可以与Tomcat集成的软件还有很多。 二、Jboss JBoss是...
  • CNN几种经典模型比较

    万次阅读 2017-03-24 21:16:26
    基于这样的观点:(尤其是)图像的特征分布在整张图像上,以及带可学习参数的卷积是一用少量参数在多个位置上提取相似特征的有效方式。在那时候,没有 GPU 帮助训练,甚至 CPU 的速度也很慢。因此,能够保存...
  • 几种常见的加密算法及 Java 实现

    万次阅读 2018-08-22 19:40:54
    本文主要对加密算法做个概况性的介绍,然后给出几种简单的加密算法 Java 实现。 1. 算法种类 单向加密 对称加密 非对称加密 1.1 单向加密 即加密之后不能解密,一般用于数据验证 1) Base64 Base64 ...
  • 几种常见设计模式的理解

    千次阅读 2015-08-31 10:58:49
    几种常见设计模式的理解 设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 最早提出“设计模式”概念的...
  • 几种ESB(企业服务总线)介绍

    万次阅读 2018-07-16 19:24:45
    ESB(Enterprise Service Bus,...企业服务总线ESB就是一可以提供可靠的、保证的消息技术的最新方法。ESB中间件产品利用的是Web服务标准和与公认的可靠消息MOM协议接口(例如 IBM的WebSphere MQ、Tibco的Rendezv...
  • 几种常见加密算法的比较

    千次阅读 2018-02-02 17:27:33
    DES加密算法是一分组密码,以64位为分组对数据加密,它的密钥长度是56位,加密解密用同一算法。DES加密算法是对密钥进行保密,而公开算法,包括加密和解密算法。这样,只有掌握了和发送方相同密钥的人才能解读由...
  • 几种主流数据库类型简介

    万次阅读 2014-04-14 21:58:43
    1.IBM的DB2  DB2是IBM出口的一系列关系型数据库管理系统,分别在不同的操作系统平台... IBM公司研制的一关系型数据库系统。DB2主要应用于大型应用系统,具有较好的可伸缩性,可支持从大型机到单用户环境,应用于
  • AI中的几种搜索算法---Tabu搜索算法

    千次阅读 2013-01-06 20:47:03
    AI中的几种搜索算法---Tabu搜索算法 引言 Tabu相对于启发式算法家族中其他成员,要简单易懂的多。关于启发式算法的基本概念可以参见笔者的《AI中的几种搜索算法---A*搜索算法》。这里就不多介绍了。 一、Tabu搜索...
  • 几种常见嵌入式实时操作系统简介

    千次阅读 2019-05-23 16:17:43
    是美国microsoft公司推出的嵌入式操作系统,支持众多的硬件平台,其最主要特点是拥有与桌上型windows家族一致的程序开发界面,因此,桌面操作系统windows家族开发的程序可以直接在windows ce上运行,主要应用于PDA...
  • Windows Server 2003 家族产品支持两授权模式: * 每设备或每用户 * 每服务器下图说明了这两模式:如果您选择“每设备或每用户”模式,那么访问运行 Windows Server 2003 家族产品的服务器的每台设备或每个...
  • 【总结】实现空格的几种方法

    千次阅读 2018-03-10 17:13:45
    中文字间无论有几个空格都会被当作一个看,这个时候就可以用到html中的几种空格实体了。它们拥有不同的宽度,非断行空格(&amp;nbsp ;)是常规空格的宽度,可运行于所有主流浏览器。其他...
  • 常见的几种视频和音频格式

    千次阅读 2008-05-14 14:04:00
    常见的几种视频和音频格式视频格式一般分为影像格式(Video Format)和流格式(Stream Video Format) 一、影像格式1.AVI格式(audio video interleaved) 播放软件:(Windows Media Player,DivX Player, QuickTime ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 54,819
精华内容 21,927
关键字:

家族分为几种