一.柏拉图原则1.用java角度谈一切皆类型面向对象范式的第一原则是柏拉图法则,它是对象技术的观念范式和心理范式的根源,对象技术是通过颠倒的理念世界而模拟唯物的真实世界。★柏拉图法则:类的世界独立存在,对象世界由类创建而来提出的依据:(1)对象(object)是一个具有浓郁的哲学味道的术语,原意是指用一种或多种(人的)感官,尤其指用视觉或触觉可以感觉到的东西、物体或物品。真实世界就是由对象/客体组成的。(2)人们看见这条黄狗、那条哈巴狗,这时,人类发挥其抽象(v.abstract)能力,从一个个的具体对象中提炼出类别/类型性的概念‘狗’或‘Dog’。进一步的演化则令人困惑——人类抽象出一些没有直接的物理对应物的概念。例如,几何中的“圆”,现实生活中没有一个对象能完全满足圆在数学上的完备性,即使小心翼翼地使用圆规。(3)软件的问题域是真实世界的一部分。柏拉图的理念论,正好适用于软件的解域:一切皆概念/类型!2.用面向对象方面说明柏拉图原则的意义二.Parnas原则(接口与实现分离)1.从c语言角度说明接口与实现分离(视角方面)2.Java角度来谈Parnas面向对象领域的推广3.什么是封装三.依赖抽象原则1.抽象依赖,开放封闭原则,针对接口编程什么区别,解释、2.Java代码说明依赖注入三种方式依赖注入模式依赖注入(DependencyInjection)是一个非常简单的概念。如例程1-5所示,Client依赖于抽象类型(甚至是具体类)IServer,但是Client的类体中不创建IServer的(子类)对象,它不关心如何初始化IServer变量,而是提供public的构造器Client(IServer)或设置方法setIServer(IServer)等,坐等外界将初始化后的IServer对象(的引用)传递进来。依赖注入模式的基本思想是客户类Client不用自己来初始化它所依赖的成员变量IServer,使用一个独立的对象创建IServer的适当的实现类并将它赋值给Client的成员变量。依赖注入的意义,在于保证Client仅仅与(通常是接口或抽象类)IServer耦合,而不与IServer的子类型耦合,这样的程序符合OCP或依赖于抽象类型原则。只要知道方法参数的意义是什么,依赖注入不过是简单的应用。1.例程1-52.packagecreational;3.importjava.lang.reflect.*;4.importtool.God;5.publicclassClient{6.privateIServers;/*依赖注入*/7.publicClient(IServers){this.s=s;}8.publicvoidsetS(IServers){this.s=s;}9.publicstaticvoidtest(){//使用工具God10.IServers=(IServer)God.create(1-4);11.s.m();}}2.1注入的方式站在Client的角度,Client接受注入有3种的方式。1.构造器注入构造器注入(ConstructorInjection)时,客户类Client提供了public的构造器Client(IServers),等待外界创建IServer的(实现类的)对象后将其引用传递进来/注入。publicClient(IServers){this.s=s;}2.Setter注入Setter注入(SetterInjection)时,客户类Client提供setIServer(IServers),等待外界创建IServer的(实现类的)对象后将其引用传递进来/注入。publicvoidsetIServer(IServers){this.s=s;}构造器注入与Setter注入是两种常用的方式。构造器注入的优点是创建Client对象时,确保IServer对象被初始化;而采用Setter注入,则创建Client对象后,必须在适当的时候调用setIServer()方法,这就使得程序员可以在灵活的时间(例如希望惰性初始化)要求外界完成注入。3.接口注入接口注入相当于将Setter注入的setIServer(IServers)方法封装到一个专用的接口如InjectIServer中,而Client实现InjectIServer并给出如下的方法体。@OverridepublicvoidsetIServer(IServers){this.s=s;}接口注入针对的场景是,有大量Client、Client1等都需要依赖于IServer。publicinterfaceInjectIServer{publicvoidsetIServer(IServers);}代码中使用了[4.1虚域模式]。然而这一方式并不一定被各种依赖注入容器所支持。3.使能工具(说明依赖注入是抽象依赖原则的使能工具,根据依赖注入实现抽象依赖?)依赖注入容器/框架依赖注入模式中,Client等待外界或一个独立的对象——称为注射器——创建IServer的适当的实现类并将它赋值给Client的成员变量。3.1显然,这个注射器不应该是系统中的某个类:1./*2.classInjection{//注射器不应该是这样的3.publicstaticvoidtest(){4.IServers=newServer();5.Clientc=newClient();6.c.setIServer(s);//注入7.c.show();}}*/这里Injection依赖于Server,如果它和Client在一个包中,就使得早期的目标——Client仅与IServer耦合破坏殆尽,还不如Client直接与具体类Server耦合。3.2由于我们拥有工具类tool.God,在任何应用程序App中,可以用God作为注射器。因而,依赖注入意味着使用反射机制创建对象。代码中,IServer对象的创建使用了tool.God的静态方法create(),create()不过是一个使用反射+属性配置文件(.properties文件)创建对象的静态工厂。1.packagecreational.di;2.importtool.God3.publicclassApp{//Injection4.publicstaticvoidtest(){5.IServers=(IServer)God.create(1-6);//1-6=creational.di.Server6.Clientc=newClient();7.c.setIServer(s);//注入8.c.show();}}★单就学习设计模式而言,工具类God已经足够。站在Client的角度,依赖注入模式对待外界创建并传入对象。请注意,至少到目前为止,我们没有说任何特别的术语——依赖倒置原则DIP和控制反转IoC,而此时,我会将依赖注入(DependencyInjection)作为一种设计模式。(也就是说,依赖注入与IoC不是同一个概念)3.3但是,比工具类God更为强大的依赖注入容器,如Spring、PicoContainer等,它们认为使用/依赖关系是面向对象编程的最基本的程序结构,各种各样的使用关系如Client与IServer、C与S等等广泛存在,作为一个依赖注入的工具或框架,希望程序员不再编写如下代码:Clientc=newClient();IServers=(IServer)God.create(1-6);c.setIServer(s);//注入c.show();设想一下,如果Client依赖很多的类似IServer的服务类型,省略掉上述阴影标识的代码,将能够节省程序员大量的时间。各种用于依赖注入的专用框架被开发出来如Spring等,它们被称为依赖注入或控制反转容器(DI/IoCContainer)。四.好莱坞原则、单向依赖1.介绍好莱坞法则。单向依赖原则2.Java演示轮询,轮询vs通知的优缺点在分层架构中,上层模块Client调用了下层模块Server的copy()方法,上层并不清楚复制的进度而只有下层的Server才知道。上层获得进度数据的方式:轮询和通知。通知的代码见回调与Java8的λ表达式。2.1轮询。下层模块Server0将进度数据保存在一个成员变量x中,并提供getX()。Client通过轮询访问该数据。轮询方式下,一个线程中Server0努力的复制,主线程则在while(true)中随时随地的查询数据,直到复制进度数据为100才结束。1.packageprinciple.callback.lower;2.publicclassServer0{3.privateintx;//复制工作的进度4.publicintgetX(){returnx;}5.publicvoidcopy(){6.while(x100){7.try{Thread.sleep(10);8.x++;}catch(InterruptedExceptione){}}}}9.packageprinciple.callback;10.importprinciple.callback.lower.Server0;11.publicclassClient0{12.privateServer0server=newServer0();13.publicvoidcall(){server.copy();}14.publicstaticvoidtest()throwsInterruptedException{15.Client0c=newClient0();16.Runnabler=()-c.call();17.newThread(r).start();18.System.out.print(进度:);19.intx2=0;20.while(true){intx1=c.server.getX();///1021.Thread.sleep((int)(Math.random()*100));22.if(x2=100){System.out.println();23.break;}24.if(x2!=x1){System.out.print(x1+%);25.x2=x1;}}}}下面是两次测试的结果。进度:3%5%9%16%21%23%29%31%38%48%57%63%70%76%82%85%87%88%90%91%97%100%进度:1%6%12%16%24%31%39%47%49%54%61%64%67%77%83%90%100%2.2轮询与通知的优缺点:轮询为系统服务资源分配提供了非竞争的访问控制机制,其控制实现过程简洁可靠,可以和有效避免接入对象间的竞争冲突,特别在高负载情况下能够获得较优的共享资源利用率。轮询的;轮询调度的缺点就是没有优先级限制,只按照先设计好的轮询顺序进行调度,再就是占用大量服务器系统资源,编程难度高,实时性差。通知为系统资源分配提供了优先级,可以按照事件的优先级进行调度。实时性好,比适适合保护方面的通信方式;缺点就是其控制过程比较复杂,接入对象存在竞争冲突。(补)轮询方式的优点:上层模块能够随时随地的了解所需的数据(不会被下级欺瞒),依赖关系和方法调用关系都很明确;下层模块代码简洁。缺点:上级时刻盯着下级干活,比较讨嫌;获得数据时执行太多的调用(特别是在网络编程如远程方法调用时,这是不能够容忍的);回调例子:它由上层模块Client、TestCallback和下层被调用者Server和公共模块IClient组成。Client的callback(int)方法被称为回调。而IClient定义的抽象方法callback(int)被称为回调接口,大多数情况下,回调接口也简称回调。1.packageAPI.event.lower;2./*通常在公共模块中设计一个抽象类或接口如IClient,定义回调的契约/规范。公共模块通常有自己的包。3.publicinterfaceIClient{4./*回调接口,参数为底层将上传的数据例如copy的进度。*/5.