设计模式(Design Patterns)
——可复用面向对象软件的基础
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。
一、设计模式的分类
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
其实还有两类:并发型模式和线程池模式。用一个来整体描述一下:
二、设计模式的六大原则
1、开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。
里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。
LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
5、迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。
三、Java的23中设计模式
从这一块开始,我们详细介绍Java中23种设计模式的概念,应用场景等情况,并结合他们的特点及设计模式的原则进行分析。
1、工厂方法模式(Factory Method)
工厂方法模式分为三种:
11、普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。首先看下关系图:
举例如下:(我们举一个发送邮件和短信的例子)
首先,创建二者的共同接口:
[java]view plaincopy publicinterfaceSender{publicvoidSend();}
其次,创建实现类:
[java]view plaincopy publicclassMailSenderimplementsSender{@OverridepublicvoidSend(){Systemoutprintln("thisismailsender!");}} [java]view plaincopy publicclassSmsSenderimplementsSender{@OverridepublicvoidSend(){Systemoutprintln("thisissmssender!");}}
最后,建工厂类:
[java]view plaincopy publicclassSendFactory{publicSenderproduce(Stringtype){if("mail"equals(type)){returnnewMailSender();}elseif("sms"equals(type)){returnnewSmsSender();}else{Systemoutprintln("请输入正确的类型!");returnnull;}}}
我们来测试下:
publicclassFactoryTest{publicstaticvoidmain(String[]args){SendFactoryfactory=newSendFactory();Sendersender=factoryproduce("sms");senderSend();}}
输出:this is sms sender!
22、多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。关系图:
将上面的代码做下修改,改动下SendFactory类就行,如下:
[java]view plaincopypublicclassSendFactory{publicSenderproduceMail(){ returnnewMailSender();}publicSenderproduceSms(){returnnewSmsSender();}}
测试类如下:
[java]view plaincopy publicclassFactoryTest{publicstaticvoidmain(String[]args){SendFactoryfactory=newSendFactory();Sendersender=factoryproduceMail();senderSend();}}
输出:this is mailsender!
33、静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
[java]view plaincopy publicclassSendFactory{publicstaticSenderproduceMail(){returnnewMailSender();}publicstaticSenderproduceSms(){returnnewSmsSender();}} [java]view plaincopy publicclassFactoryTest{publicstaticvoidmain(String[]args){Sendersender=SendFactoryproduceMail();senderSend();}}
输出:this is mailsender!
总体来说,工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。
2、抽象工厂模式(Abstract Factory)
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。因为抽象工厂不太好理解,我们先看看图,然后就和代码,就比较容易理解。
请看例子:
[java]view plaincopy publicinterfaceSender{publicvoidSend();}
两个实现类:
[java]view plaincopy publicclassMailSenderimplementsSender{@OverridepublicvoidSend(){Systemoutprintln("thisismailsender!");}} [java]view plaincopy publicclassSmsSenderimplementsSender{@OverridepublicvoidSend(){Systemoutprintln("thisissmssender!");}}
两个工厂类:
[java]view plaincopy publicclassSendMailFactoryimplementsProvider{@OverridepublicSenderproduce(){returnnewMailSender();}} [java]view plaincopy publicclassSendSmsFactoryimplementsProvider{@OverridepublicSenderproduce(){returnnewSmsSender();}}
在提供一个接口:
[java]view plaincopy publicinterfaceProvider{publicSenderproduce();}
测试类:
[java]view plaincopy publicclassTest{publicstaticvoidmain(String[]args){Providerprovider=newSendMailFactory();Sendersender=providerproduce();senderSend();}}
其实这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好!
3、单例模式(Singleton)
单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:
1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
2、省去了new *** 作符,降低了系统内存的使用频率,减轻GC压力。
3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。
首先我们写一个简单的单例类:
[java]view plaincopy publicclassSingleton{/持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载/privatestaticSingletoninstance=null;/私有构造方法,防止被实例化/privateSingleton(){}/静态工程方法,创建实例/publicstaticSingletongetInstance(){if(instance==null){instance=newSingleton();}returninstance;}/如果该对象被用于序列化,可以保证对象在序列化前后保持一致/publicObjectreadResolve(){returninstance;}}
这个类可以满足基本要求,但是,像这样毫无线程安全保护的类,如果我们把它放入多线程的环境下,肯定就会出现问题了,如何解决?我们首先会想到对getInstance方法加synchronized关键字,如下:
[java]view plaincopy publicstaticsynchronizedSingletongetInstance(){if(instance==null){instance=newSingleton();}returninstance;}
但是,synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了,所以,这个地方需要改进。我们改成下面这个:
[java]view plaincopy publicstaticSingletongetInstance(){if(instance==null){synchronized(instance){if(instance==null){instance=newSingleton();}}}returninstance;}
似乎解决了之前提到的问题,将synchronized关键字加在了内部,也就是说当调用的时候是不需要加锁的,只有在instance为null,并创建对象的时候才需要加锁,性能有一定的提升。但是,这样的情况,还是有可能有问题的,看下面的情况:在Java指令中创建对象和赋值 *** 作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个 *** 作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了,我们以A、B两个线程为例:
a>A、B线程同时进入了第一个if判断
b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();
c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。
d>B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。
e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。
所以程序还是有可能发生错误,其实程序在运行过程是很复杂的,从这点我们就可以看出,尤其是在写多线程环境下的程序更有难度,有挑战性。我们对该程序做进一步优化:
[java]view plaincopy privatestaticclassSingletonFactory{privatestaticSingletoninstance=newSingleton();}publicstaticSingletongetInstance(){returnSingletonFactoryinstance;}
实际情况是,单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。这样我们暂时总结一个完美的单例模式:
[java]view plaincopy publicclassSingleton{/私有构造方法,防止被实例化/privateSingleton(){}/此处使用一个内部类来维护单例/privatestaticclassSingletonFactory{privatestaticSingletoninstance=newSingleton();}/获取实例/publicstaticSingletongetInstance(){returnSingletonFactoryinstance;}/如果该对象被用于序列化,可以保证对象在序列化前后保持一致/publicObjectreadResolve(){returngetInstance();}}
其实说它完美,也不一定,如果在构造函数中抛出异常,实例将永远得不到创建,也会出错。所以说,十分完美的东西是没有的,我们只能根据实际情况,选择最适合自己应用场景的实现方法。也有人这样实现:因为我们只需要在创建类的时候进行同步,所以只要将创建和getInstance()分开,单独为创建加synchronized关键字,也是可以的:
[java]view plaincopy publicclassSingletonTest{privatestaticSingletonTestinstance=null;privateSingletonTest(){}privatestaticsynchronizedvoidsyncInit(){if(instance==null){instance=newSingletonTest();}}publicstaticSingletonTestgetInstance(){if(instance==null){syncInit();}returninstance;}}
考虑性能的话,整个程序只需创建一次实例,所以性能也不会有什么影响。
补充:采用"影子实例"的办法为单例对象的属性同步更新
[java]view plaincopy publicclassSingletonTest{privatestaticSingletonTestinstance=null;privateVectorproperties=null;publicVectorgetProperties(){returnproperties;}privateSingletonTest(){}privatestaticsynchronizedvoidsyncInit(){if(instance==null){instance=newSingletonTest();}}publicstaticSingletonTestgetInstance(){if(instance==null){syncInit();}returninstance;}publicvoidupdateProperties(){SingletonTestshadow=newSingletonTest();properties=shadowgetProperties();}}
通过单例模式的学习告诉我们:
1、单例模式理解起来简单,但是具体实现起来还是有一定的难度。
2、synchronized关键字锁定的是对象,在用的时候,一定要在恰当的地方使用(注意需要使用锁的对象和过程,可能有的时候并不是整个对象及整个过程都需要锁)。
到这儿,单例模式基本已经讲完了,结尾处,笔者突然想到另一个问题,就是采用类的静态方法,实现单例模式的效果,也是可行的,此处二者有什么不同?
首先,静态类不能实现接口。(从类的角度说是可以的,但是那样就破坏了静态了。因为接口中不允许有static修饰的方法,所以即使实现了也是非静态的)
其次,单例可以被延迟初始化,静态类一般在第一次加载是初始化。之所以延迟加载,是因为有些类比较庞大,所以延迟加载有助于提升性能。
再次,单例类可以被继承,他的方法可以被覆写。但是静态类内部方法都是static,无法被覆写。
最后一点,单例类比较灵活,毕竟从实现上只是一个普通的Java类,只要满足单例的基本需求,你可以在里面随心所欲的实现一些其它功能,但是静态类不行。从上面这些概括中,基本可以看出二者的区别,但是,从另一方面讲,我们上面最后实现的那个单例模式,内部就是用一个静态类来实现的,所以,二者有很大的关联,只是我们考虑问题的层面不同罢了。两种思想的结合,才能造就出完美的解决方案,就像HashMap采用数组+链表来实现一样,其实生活中很多事情都是这样,单用不同的方法来处理问题,总是有优点也有缺点,最完美的方法是,结合各个方法的优点,才能最好的解决问题!
4、建造者模式(Builder)
工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。我们看一下代码:
还和前面一样,一个Sender接口,两个实现类MailSender和SmsSender。最后,建造者类如下: [java]view plaincopy publicclassBuilder{privateList list=newArrayList ();publicvoidproduceMailSender(intcount){for(inti=0;i0){pos--;}returncollectionget(pos);}@OverridepublicObjectnext(){if(pos
分为网页和桌面的应用开发
网页或者桌面开发流程
项目启动
1)、项目组成立(公司成员、客户成员)
2)、制定项目预期目标
3)、制定项目计划周期
4)、建立好项目组成员沟通机制
2、需求调研
1)、创建调研计划、协调调研时间
2)、收集客户资料,获取客户需求所有的资料都需要保留一份,资料中存疑的需要及时询问
3)、编写需求文档重点描述出客户的业务流程和性能要求。采用Word、Excel、Rose等形式。
4)、需求变更记录
5)、确定开发环境和运行环境
6)、扩展性要求
7)、与旧系统的接驳要求。
8)、估算出项目工作量本阶段需要一套需求管理系统来进行需求的管理。本阶段的需求文档也是用户测试的依据。
3、系统设计/详细设计一个系统可以分为基础平台和应用模块两部分。
1)、选择基础平台,无论是采用第三方平台还是自行开发平台,都需要深入了解,查看是否符合要求。
2)、应用模块设计(针对业务流程)
3)、中间件的采用或自行开发,需要深入了解。
4)、用户界面的设计如果用户界面设计完毕并确认,即可初步写出用户使用手册、管理员使用手册。
5)、变更记录本阶段的系统设计是集成测试的依据。
4、程序开发创建开发任务计划表、开发计划日程表
1)、优先编写测试用例
2)、按照编码规范编写代码
3)、按照文档注释规范注释以上形成开发文档。本阶段需要一套版本管理系统。本阶段的测试用例也是单元测试的依据。如果能做到,最好每日构建。
5、测试本阶段需要一套Bug管理系统,形成需求、设计、开发、测试互动。
1)、编写测试计划和测试方案
2)、功能测试单元测试、集成测试
3)、性能测试集成测试、压力测试如果能做到,最好能进行自动化测试。如果能做到,做分析统计工作。最后形成测试报告。
6、试用、培训、维护本阶段需要解决:
1)、解决异地修改和公司修改的同步问题。
2)、用户测试中的Bug修改问题,按照级别分为a)、程序Bugb)、设计变更c)、需求变更尽量按照abc的顺序来进行修改,尽量避免b、c级的修改。最后形成安装手册、维护记录。
题主的问题很有代表性,尤其是对企业信息化建设前期进行技术选型时,需要重点考虑。根据本人经验,通过Java开发平台做平台开发时,建议关注以下几个方面:
第一、统筹开发目标,关注系统架构设计,
如果你的目标是建设一个平台,那就说明不是一个小项目,一定要明确开发目标(尤其是阶段性里程碑目标)。在项目整体目标明确后,做好系统架构设计。系统架构设计不聚焦在Java开发平台上,而是界定好平台内部各个功能模块(或业务组件)之间的关系,确定通信机制和访问协议。如果是计划建设的平台规模较大(如:将来计划用户量上千万,或后台数据TB级别),可能还需要做好中台建设(关于中台的建设此处不再展开),但一个信息化平台至少包含以下几个部分:
权限体系安全体系数据访问体系接口通信体系基础功能体系业务功能体系用户交互体系一闪几个部分架构:
▲通用系统架构
第二、尽量做到功能解耦,强化系统可扩展性
Java开发一大优点是可实现跨平台运行,无论是Windows服务器还是Linux服务器,只需要安装JVM和JDK即可,从而实现了开发程序和 *** 作系统的解耦。但平台建设最难的是业务功能的解耦。几乎所有平台都会涉及到安全体系、权限体系、跨域访问等问题。在平台架构设计完善后,务必要将业务功能解耦,将公共调用的功能模块抽象出来,形成独立的组件,尤其是涉及到后台算法和性能的组件,更需要从具体业务模块中抽象出来。在组件调用时形成固定通用的调用接口,可以使封装后调用,也可以是代码级、工程级引用。这样既可做到平台业务可扩展,也增强了后续升级迭代的便捷性。
▲功能解耦示意图
第三、用成熟的第三方组件,强调代码可维护性
Java另一特点是其庞大的开源体系,可以从GitHub上获得巨量支持。通常我们可以引入第三方成熟的组件,以快速高效实现特定系统功能的效果。但引入第三方组件时,最好遵循开源和成熟的原则。以便在业务调整,需要修改组件涉及到的相关功能时,可直接修改组件相关源码。
另外,Java开发时养成良好的编码习惯,增强代码可维护性也非常必要。尤其是平台核心代码,最好做好注解解释,并对版本进行控制,以便升级迭代 *** 作。
▲Spring框架的核心代码示例
希望以上三点能帮到您!
比如,我们如果想得到一个网页上所有包括“java”关键字的文本内容,就可以逐行对网页代码进行正则表达式的匹配。最后达到去除html标签和不相关的内容,只得到包括“java”这个关键字的内容的效果。
从网页上爬取的流程和爬取内容的流程基本相同,但是爬取的步骤会多一步。
需要先用img标签的正则表达式匹配获取到img标签,再用src属性的正则表达式获取这个img标签中的src属性的url,然后再通过缓冲输入流对象读取到这个url的信息,配合文件输出流将读到的信息写入到本地即可。
1、使用表单发送同步请求,实现数据交互。参数inputStr,参数intputlnt。
2、jave分布式开发采用服务端后台进行实现接收模块之间的数据交互,点击服务器端来交换,点击确认即可。
很多Java开发者对模块化编程仍然接触不多 对Java的模块化的进展也不甚了解 多方观望 年将是Java模块化的一年 因此 CTO编辑希望能在这一年中让更多的开发者了解模块化编程的概念 它的学习 实现方式以及它的好处 为此 我们请来了一位国内的OSGi布道者为大家进行一次简单的普及介绍
有请China OSGi User Group Director 淘宝网平台架构部架构师——林昊(@BlueDavy) 林昊是《OSGi原理与最佳实践》一书的作者
此次采访模式为邮件采访 林昊对 CTO编辑提出的 个问题一一进行了回复 内容如下
模块的实现和传统编程方法有何不同?开发者需要学习哪些知识(比如版本控制 依赖性管理 规范的接口设计等)?
林昊 模块的实现和传统的编程方法确实有一些差别 主要体现在模块之间类访问的隔离 版本选择这两个方面 如希望更好的设计模块化的系统 开发者需要学习ClassLoader机制 模块之间类的交互方法(这包括了模块怎么样对外提供可访问的package 怎么样访问其他模块提供的package 如何选择适合版本的package等)
对模块化的形容 我们往往使用 高内聚 低耦合/松散耦合 这样的用语 您是如何理解这两个概念的?
林昊 高内聚 低耦合更多程度是指让模块之间的依赖是清晰的 内聚体现在内部对功能实现的封装 而低耦合体现在模块对外提供的接口是可控的 在模块化之前 在Java体系中更多的是通过public protected private这样的作用域来保证依赖清晰(参考阅读 模块化概念解惑) 但事实证明 这样的方法来保证不是非常有效 而在模块化的体系中 则会有明确的模块之间接口暴露以及依赖的定义 因此能够更好的实现高内聚和低耦合
模块化编程的好处有哪些?它解决了原来那种紧密耦合式编程中存在的哪些问题?
林昊 模块化编程最大的好处在于有效的控制和避免了模块被外部误用 其他方面的好处在于各模块可以方便的做到引用自己所需要依赖的包 避免产生包冲突现象 对于现有java体系而言 另外一个好处则是可以做到多版本的共存
您觉得模块化编程最大的难点在哪里?在您的模块化开发过程中 理清逻辑和层次所花的时间和编写代码花费的时间大致是怎样的比例?
林昊 模块化编程最大的难点一方面是设计方面的挑战 在没有实际隔离情况下模块化的设计其实并不会真正做到有效的模块隔离的设计 另一方面是在开发过程中 以前的开发习惯都需要改变 例如以前需要依赖其他模块时 可以采用直接依赖工程或依赖jar的方式 但在模块化的系统中则不行
在实际的模块化开发过程中 更多的时间仍然会花费在设计阶段
我们来谈谈OSGi规范 OSGi模块化规范有什么特点?
林昊 OSGi是Java中目前唯一的一个模块化 动态化的规范 在模块化方面OSGi联盟已经研究了很多年了 因此OSGi规范对于模块的物理隔离 模块的交互 多版本这些方面都有了非常完善的机制 并且也得到了现在几乎所有的App Server厂商或开源社区的认可
虽然OSGi已经是有十多年发展的成熟的模块化标准 但Sun在对Java进行模块化的时候却选择采用JSR 并在Java 当中开展Jigsaw项目 您对此有什么看法?
林昊 JCP在关于Java 纳入模块化后到底采用什么标准争论了非常久 JSR 是个研讨了多年的规范 但最后不了了之 Sun现在另起炉灶做Jigsaw 但其实并没有得到多大的拥护 各App Server仍然采用OSGi作为其基础平台就是最好的证明(参考阅读 JSR 被叫停 应用服务器押宝OSGi) 可以说现在OSGi已经是Java领域模块化 动态化的事实性标准
您认为理想的Java模块化标准应该具备怎样的特点?您对Java模块化的发展有怎样的期待?
林昊 Java模块化标准应有明确的模块定义 模块之间隔离机制的定义 模块交互机制的定义 个人认为在模块化这一方面OSGi已经做到非常好了 当然 如果是语言级能支持就更完美了
lishixinzhi/Article/program/Java/hx/201311/27136
以上就是关于Java开发中的23种设计模式详解(转)_Java开发模式全部的内容,包括:Java开发中的23种设计模式详解(转)_Java开发模式、Java程序开发步骤、想选用一个Java快速开发平台为基础进行开发和平台建设,有什么建议等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)