小米售后检测要钱吗能远程检测吗

简单介绍一下工厂模式,单例模式以及模板模式 -
- ITeye博客
博客分类:
设计模式:工厂模式、单例模式、模板模式
1.简单工厂模式:
&&&& a.概述:
&&& 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程(new 关键字和具体的构造器)隐藏起来。用一个工厂方法来替代,对外提供的只是一个工厂方法,达到提高灵活性的目的。
&&&& b.优点:
&&&&&&&&&& 1.隐藏了new关键字和构造器
&&&&&&&&&& 2.降低了这个对象与别的类之间的耦合度,提高了程序的可扩展性。
&&&&&&&&&&&& 原因:当子类被别的类替代,或者构造器的参数发生变化的时候,只需改动工厂方法内的new即可,改动量降到了最低,而如果不用工厂模式,而是直接用new关键字的话,需要改动的地方就很多了
&&&&&&&&&& 3.把对象的设计和实现分割开来,从而代码扩展性强、灵活性高。
&&&& c.工厂模式的使用范围:
&&&&&& 当遇到下面的情况时,开发人员可以考虑采用工厂模式:
&&&&&& * 在编码时不能预见需要创建哪一个种类的实例。
&&&&&& * 一个类使用它的子类来创建对象。
&&&&&& * 开发人员不希望创建了那个类的实例以及如何创建实例的信息暴露给外部程序。
&&&&& 除了上面提到的例子,工厂模式的实现方式还允许有一些小小的变化,例如:
&&&&&& * 基类可以是一个抽象类,在这种情况下,工厂类必须返回一个非抽象类。
&&&&&& * 基类提供了一些缺省方法,只有当这些缺省方法不能满足特殊需求的情况下才能在子类中重写这些方法。
&&&&&& * 可以直接通过传递给工厂类的参数决定应该返回哪一个子类的实例。
&&&& d. 使用工厂模式,它的设计期于运行期的对象不同,这样就增强了代码的可扩展性。
&&&&&&& 它把构造器隐藏了起来,降低了代码的耦合度,增强了代码的复用性。
&&&&&&& 工厂模式与new的比较:如果使用new关键字的话,那么如果这个类的对象在很多的地方用到,必须要使用多次的new操作,这样容易引起代码的重复使用,如果需要改动或者替换成这个类的子类对象,那么,就需要把执行了new操作的所有地方都要改,比较麻烦。而工厂模式,因为它代替了构造器和new关键字,而且,它是使用面向接口的,所以,需要这个类的对象的时候,只需要调用这个方法就可以了,如果,需要改动或者替换成这个类的子类对象。只要修改这个工厂里面的内容,而其他的地方都不需要改动。
&&&&&&&&& 工厂模式的结构是:用一个方法来代替new关键字和构造器。
&& 单例模式:
&&&&&& 分类
&
&& 一。单例模式的四大特征:
&&&&&& 懒汉式:
&&&&&&& 1。声明一个私有的,静态的本类对象,但并不在声明的时候就初始化,因此,它& 的值为null。
&&&&&&& 2。私有化构造器
&&&&&&& 3。对外提供一个全局的,共有的,静态的,唯一的方法,用来获得该实例,但注意的是:必须要手动保持线程同步(synchronized)
&&&&&&& 4.在该方法里,判断对象是否为null,如果是null的话,表示这个类还没有被实例化,就会初始化这个对象,再返回如果不是null的话,就直接返回。
& 饿汉式:
&&&&&&& 1.声明一个私有的,静态的本类对象,并在声明的时候就初始化
&&&&&&& 2.私有构造器
&&&&&&& 3.对外提供一个全局的,共有的,静态的,唯一的方法,用来获得该实例(饿汉式线程本身就是同步的)
&&&&&&& 4.在该方法里,直接返回该对象即可
&&& 从资源利用效率角度来讲,这个比懒汉式单例类稍微差些。从速度和反应时间角度来讲,则比懒汉式单例类稍好些。
&&&
&&&& 二、它能解决什么问题:
&&&&& 它确保一个类在java虚拟机里只有一个实例,使一个类只有一个对象,整个系统共享这个对象。
&&&& 三、什么时候使用懒汉式和饿汉式:
&&&&&&&& 1。 在使用的几率很少的情况下使用懒汉式。 --用的时候实例
&&&&&&&& 2。 而使用的几率很高的话就用饿汉式。--一开始就初始化实例
&&&& 四、单例模式的好处:
&&&&&&&& 整个系统中的所有的类共用一个实例化对象,这样可以有效的节省资源。
& 模板模式:
&&&&&&& 模板模式是多个实现类继承一个抽象父类,然后通过抽象父类控制顶级逻辑,并把基本操作的实现推迟到子类去实现,这样能有效简化控制层诸类的代码,借用这种模式,我们可以把固定的异常处理代码放在基类中,而让子类来实现具体的业务,如果执行业务过程中出现异常如数据库无法连接,用户找不到异常后,直接将异常抛出让基类来处理,这样做成功的把业务处理和异常分开到了子类和基类两种类中,涉及具体业务处理的子类代码得到了很大的简化,更方便阅读,修改和管理。
&&&&& 1。父类定义流程,子类实现:
&&&&&&&& 模板模式解决了子类有大量重复的流程,重复的方法,重复的变量时的问题,不同的子类间都有的方法,抽取出来放在父类中。子类都有的流程,在父类中定义好其流程,流程的具体实现就交给子类来实现。
&&&&& 2。模板方法的目的。
&&&&&& A 减少重复代码。
&&&&&& B 防止调用出错。
&&&&& 3。使用模板方法的步骤:
&&&&&&& A、识别:从一些列的算法中去找到,它们的共同部分在哪儿,称之为识别。
&&&&&&& B、分离:将不同的代码抽取出来,称之为分离。
&&&&&&& C、实现:用继承将抽取出来的方法在子类中予以实现。
&&&&& 4。模板模式的好处:
&&&&&&&&& 模板模式可以把子类中你给一些公用的代码全部放到公共的父类中共享,增加了代码的服用性,然后,可以在父类中定义程序的流程,而子类只需要实现流程中定义的抽象方法,这样子,可以为一个项目的团队开发提供了方便,使代码更加清晰,由于父类式一个抽象类,这就使得父类中的代码只能在子类中所见,增加了代码的安全性,但系统中有变动时,使用模板模式可以解决不必要的麻烦。
BabyDuncan
浏览: 355278 次
来自: 北京
好文章,顶顶
hugh.wang 写道请问你这个能还原吗?短网址用的是HAS ...
没有注释,看的费劲
好帖子竟然没人顶...
不好,你这只是记录式的博客,不是分享式的博客,对浏览着不友好. ...软件开发的家园,编程爱好者的天地.
&&|&&&&|&&
设计模式之Factory
来源:互联网
时间: 20:42
定义:提供创建对象的接口.为何使用?工厂模式是我们最常用的模式了,著名的Jive论坛系统,就大量使用了工厂模式.为什么说工厂模式是最常用,因为工厂模式就相当于创建对象的new.工厂模式就是用来创建对象的.比如我们有一个类Sample我们要创建Sample的对象:Samplesample=newSample();如果我们要在创建sample之前做点事情,比如,赋值等,可以使用Sample的构造函数:Samplesample=newSample(参数);如果创建sample时做的事情不是如赋值这样简单的事,可能是很长一段代码,如果也写入构造函数中,那明显的就违背了面向对象的原则.封装(Encapsulation)和分派(Delegation);我们需要将创建实例的责任与使用实例的责任分开,使得语句Samplesample=newSample(参数);就是简单的责任:使用Sample这个实例;至于创建Sample的任务就交给了Factory工厂模式.还有,如果Sample有个继承如MySample,按照面向接口编程,我们需要将Sample抽象成一个接口.现在Sample是接口,有两个子类MySample和HisSample.我们要实例化他们时,如下:Samplemysample=newMySample();Samplehissample=newHisSample();随着项目的深入,Sample可能还会&生出很多儿子出来&,那么我们要对这些儿子一个个实例化,更糟糕的是,可能还要对以前的代码进行修改:加入后来生出儿子的实例.这在传统程序中是无法避免的.但如果你一开始就有意识使用了工厂模式,这些麻烦就没有了.你会建立一个专门生产Sample实例的工厂:publicclassFactory{  publicstaticSamplecreator(){  ....  if(which==1)    returnnewMySample();  elseif(which==2)    returnnewHisSample();  }}那么在你的程序中,如果要实例化MySample时.就使用Samplesample=Factory.creator();这样,在整个就不涉及到Sample的具体子类,达到封装效果,也就减少错误修改的机会,这个原理可以用很通俗的话来比喻:就是具体事情做得越多,越容易范错误.这每个做过具体工作的人都深有体会,相反,官做得越高,说出的话越抽象越笼统,范错误可能性就越少.好象我们从编程序中也能悟出人生道理?呵呵.好了,言归正传,既然不可避免使用factory,那我们就认识一下工厂模式.如何使用?工厂模式中有:简单工厂工厂方法(FactoryMethod)抽象工厂(AbstractFactory).上例中,我们使用的是简单工厂.这几个模式没有很明显的区别,在我的概念中,简单工厂应该是只有一个工厂方法,如果我们创建对象的方法变得复杂了,我们就可能要将上例中Factory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现:publicabstractclassFactory{  publicabstractSamplecreator();  publicabstractSample2creator();}publicclassSimpleFactoryextendsFactory{  publicSamplecreator(){    ......  }  publicSample2creator(){    ......  }}publicclassBombFactoryextendsFactory{  publicSamplecreator(){    ......  }  publicSample2creator(){    ......  }}上例中我们只有一类产品接口Sample,工厂方法和抽象工厂可以创建多个产品接口的实例,比如Sample2Sample3FactoryMethod往往只是创建单个的实例。AbstractFactory创建一系列的实例组,这些实例彼此相关。举例1下图是抽象工厂图:在这张图中,有两类产品接口interfaceRAM和interfaceCPU;同时有两个创建方法:MacProducer和PCProducer,这两个创建方法中都有createCPU()和createRAM(),返回的实例对象组是CPU和RAM,这是分别来自两类产品接口,表面彼此是相关的.因此它是抽象工厂.
对我有帮助
对我没帮助
以下留言只代表网友个人观点,不代表本站观点.【创建型模式一】简单工厂(Simple Factory) - 简书
【创建型模式一】简单工厂(Simple Factory)
1 场景问题
大家都知道,在Java应用开发中,要“面向接口编程”。那么什么是接口?接口有什么作用?接口如何使用?一起来回顾一下。
1.1 接口回顾
Java中接口的概念
在Java中接口是一种特殊的抽象类,跟一般的抽象类相比,接口里面的所有方法都是抽象方法,接口里面的所有属性都是常量。也就是说,接口里面是只有方法定义而不会有任何方法实现。
接口用来干什么
通常用接口来定义实现类的外观,也就是实现类的行为定义,用来约束实现类的行为。接口就相当于一份契约,根据外部应用需要的功能,约定了实现类应该要实现的功能,但是具体的实现类除了实现接口约定的功能外,还可以根据需要实现一些其它的功能,这是允许的,也就是说实现类的功能包含但不仅限于接口约束的功能。
通过使用接口,可以实现不相关类的相同行为,而不需考虑这些类之间的层次关系,接口就是实现类对外的外观。
接口的思想
根据接口的作用和用途,浓缩下来,接口的思想就是“封装隔离”。
通常提到封装是指对数据的封装,但是这里的封装是指“对被隔离体的行为的封装”,或者是“对被隔离体的职责的封装”;而隔离指的是外部调用和内部实现,外部调用只能通过接口进行调用,而外部调用是不知道内部具体实现的,也就是说外部调用和内部实现是被接口隔离开的。
接口的好处
由于外部调用和内部实现被接口隔离开了,那么只要接口不变,内部实现的变化就不会影响到外部应用,从而使得系统更灵活,具有更好的扩展性和可维护性,这也就是所谓“接口是系统可插拔性的保证”这句话的意思。
接口和抽象类的选择
既然接口是一种特殊的抽象类,那么在开发中,何时选用接口,何时选用抽象类呢?对于它们的选择,在开发中是一个很重要的问题,特别总结两句话给大家:优先选用接口。在如下情况应选择抽象类:既要定义子类的行为,又要为子类提供公共的功能。
1.2 面向接口编程
面向接口编程是Java编程中的一个重要原则。
在Java 程序设计里面,非常讲究层的划分和模块的划分。通常按照三层来划分Java程序,分别是表现层、逻辑层、数据层,它们之间都要通过接口来通讯。
在每一个层里面,又有很多个小模块,一个小模块对外也应该是一个整体,那么一个模块对外也应该提供接口,其它地方需要使用到这个模块的功能,都应该通过此接口来进行调用。这也就是常说的“接口是被其隔离部分的外观”。基本的三层结构如图1所示:
基本的三层结构
在一个层内部的各个模块交互也要通过接口,如图所示:
层内部各个模块交互
上面频频提到“组件”,那么什么是组件呢?先简单的名词解释一下:
所谓组件:从设计上讲,组件就是能完成一定功能的封装体。小到一个类,大到一个系统,都可以称为组件,因为一个小系统放到更大的系统里面去,也就当个组件而已。事实上,从设计的角度看,系统、子系统、模块、组件等说的其实是同一回事情,都是完成一定功能的封装体,只不过功能多少不同而已。
继续刚才的思路,大家会发现,不管是一层还是一个模块或者一个组件,都是一个被接口隔离的整体,那么下面我们就不去区分它们,统一认为都是接口隔离体即可,如图所示:
接口隔离体
既然在Java中需要面向接口编程,那么在程序中到底如何使用接口,来做到真正的面向接口编程呢?
1.3 不用模式的解决方案
回忆一下,以前是如何使用接口的呢,假设有一个接口叫Api,然后有一个实现类Impl实现了它,在客户端怎么用这个接口呢?
通常都是在客户端创建一个Impl的实例,把它赋值给一个Api接口类型的变量,然后客户端就可以通过这个变量来操作接口的功能了,此时具体的结构图如图:
基本的接口和实现
先定义接口Api,示例代码如下:
* 某个接口(通用的、抽象的、非具体的功能)
public interface Api {
* 某个具体的功能方法的定义,用test1来演示一下。
* 这里的功能很简单,把传入的s打印输出即可
* @param s 任意想要打印输出的字符串
public void test1(String s);
既然有了接口,自然就要有实现,定义实现Impl,示例代码如下:
* 对接口的实现
public class Impl implements Api{
public void test1(String s) {
System.out.println("Now In Impl. The input s=="+s);
那么此时的客户端怎么写呢?按照Java的知识,接口不能直接使用,需要使用接口的实现类,示例代码如下:
* 客户端:测试使用Api接口
public class Client {
public static void main(String[] args) {
Api api = new Impl();
api.test1("哈哈,不要紧张,只是个测试而已!");
1.4 有何问题
上面写得没错吧,在Java的基础知识里面就是这么学的,难道这有什么问题吗?请仔细看位于客户端的下面这句话:
Api api = new Impl();
然后再想想接口的功能和思想,发现什么了?仔细再想想?
你会发现在客户端调用的时候,客户端不但知道了接口,同时还知道了具体的实现就是Impl。而接口的思想是“封装隔离”,而Impl这个实现类,应该是被接口Api封装并同客户端隔离开的,也就是说,客户端根本就不应该知道具体的实现类是Impl。
有朋友说,那好,我就把Impl从客户端拿掉,让Api真正的对实现进行“封装隔离”,然后我们还是面向接口来编程。可是,新的问题出现了,当他把“new Impl()”去掉过后,发现他无法得到Api接口对象了,怎么办呢?
把这个问题描述一下:
在Java编程中,出现只知接口而不知实现,该怎么办?
就像现在的Client,它知道要使用Api接口,但是不知由谁实现,也不知道如何实现,从而得不到接口对象,就无法使用接口,该怎么办呢?
2 解决方案
2.1 简单工厂来解决问题
用来解决上述问题的一个合理的解决方案就是简单工厂,那么什么是简单工厂呢?
简单工厂定义
简单工厂定义
应用简单工厂来解决的思路
分析上面的问题,虽然不能让模块外部知道模块内的具体实现,但是模块内部是可以知道实现类的,而且创建接口是需要具体实现类的。
那么干脆在模块内部新建一个类,在这个类里面来创建接口,然后把创建好的接口返回给客户端,这样外部应用就只需要根据这个类来获取相应的接口对象,然后就可以操作接口定义的方法了。把这样的对象称为简单工厂,就叫Factory吧。
这样一来,客户端就可以通过这个Factory来获取需要的接口对象,然后调用接口的方法来实现需要的功能,而且客户端也不用再关心具体实现了。
2.2 简单工厂结构和说明
简单工厂的结构如图所示:
简单工厂的结构如图
Api:定义客户所需要的功能接口
Impl:具体实现Api的实现类,可能会有多个
Factory:工厂,选择合适的实现类来创建Api接口对象
Client:客户端,通过Factory去获取Api接口对象,然后面向Api接口编程
2.3 简单工厂示例代码
先看看Api的定义,示例代码如下:
* 接口的定义,该接口可以通过简单工厂来创建
public interface Api {
* 示意,具体的功能方法的定义
* @param s 示意,需要的参数
public void operation(String s);
定义了接口,该来实现它了,ImplA的示例代码如下:
* 接口的具体实现对象A
public class ImplA implements Api{
public void operation(String s) {
//实现功能的代码,示意一下
System.out.println("ImplA s=="+s);
* 接口的具体实现对象B
public class ImplB implements Api{
public void operation(String s) {
// 实现功能的代码,示意一下
System.out.println("ImplB s=="+s);
该来看看简单工厂的实现,示例代码如下:
* 工厂类,用来创造Api对象
public class Factory {
* 具体的创造Api对象的方法
* @param condition 示意,从外部传入的选择条件
* @return 创造好的Api对象
public static Api createApi(int condition){
//应该根据某些条件去选择究竟创建哪一个具体的实现对象,
//这些条件可以从外部传入,也可以从其它途径获取。
//如果只有一个实现,可以省略条件,因为没有选择的必要。
//示意使用条件
if(condition == 1) {
api = new ImplA();
} else if(condition == 2) {
api = new ImplB();
再来看看客户端的示意,示例代码如下:
* 客户端,使用Api接口
public class Client {
public static void main(String[] args) {
//通过简单工厂来获取接口对象
Api api = Factory.createApi(1);
api.operation("正在使用简单工厂");
使用简单工厂重写示例
要使用简单工厂来重写前面的示例,主要就是要创建一个简单工厂对象,让简单工厂来负责创建接口对象。然后让客户端通过工厂来获取接口对象,而不再由客户端自己去创建接口的对象了。此时系统的结构如图所示:
系统结构如图
接口Api和实现类Impl都和前面的示例一样,就不去赘述了。
新创建一个简单工厂的对象,示例代码如下:
* 工厂类,用来创造Api对象
public class Factory {
* 具体的创造Api对象的方法
* @return 创造好的Api对象
public static Api createApi(){
//由于只有一个实现,就不用条件判断了
return new Impl();
客户端如何使用简单工厂提供的功能呢?这个时候,客户端就不用再自己去创建接口的对象了,应该使用工厂来获取,经过改造,客户端代码如下:
* 客户端:测试使用Api接口
public class Client {
public static void main(String[] args) {
//重要改变,没有new Impl()了,取而代之Factory.createApi()
Api api = Factory.createApi();
api.test1("哈哈,不要紧张,只是个测试而已!");
就如同上面的示例,客户端通过简单工厂创建了一个实现接口的对象,然后面向接口编程,从客户端来看,它根本就不知道具体的实现是什么,也不知道是如何实现的,它只知道通过工厂获得了一个接口对象,然后就能通过这个接口来获取想要的功能。
事实上,简单工厂能帮助我们真正开始面向接口编程,像以前的做法,其实只是用到了接口的多态那部分的功能,最重要的“封装隔离性”并没有体现出来。
3 模式讲解
3.1 典型疑问
首先来解决一个常见的疑问:可能有朋友会认为,上面示例中的简单工厂看起来不就是把客户端里面的“new Impl()”移动到简单工厂里面吗?不还是一样通过new一个实现类来得到接口吗?把“new Impl()”这句话放到客户端和放到简单工厂里面有什么不同吗?
理解这个问题的重点就在于理解简单工厂所处的位置。
根据前面的学习,我们知道接口是用来封装隔离具体的实现的,目标就是不要让客户端知道封装体内部的具体实现。简单工厂的位置是位于封装体内的,也就是简单工厂是跟接口和具体的实现在一起的,算是封装体内部的一个类,所以简单工厂知道具体的实现类是没有关系的。整理一下简单工厂的结构图,新的图如图所示:
简单工厂的结构图
图中虚线框,就好比是一个组件的包装边界,表示接口、实现类和工厂类组合成了一个组件,在这个封装体里面,只有接口和工厂是对外的,也就是让外部知道并使用的,所以故意漏了一些在虚线框外,而具体的实现类是不对外的,被完全包含在虚线框内。
对于客户端而言,只是知道了接口Api和简单工厂Factory,通过Factory就可以获得Api了,这样就达到了让Client在不知道具体实现类的情况下获取接口Api。所以看似简单的把“new Impl()”这句话从客户端里面移动到了简单工厂里面,其实是有了质的变化的。
3.2 认识简单工厂
简单工厂的功能
工厂嘛,就是用来造东西的。在Java里面,通常情况下是用来造接口的,但是也可以造抽象类,甚至是一个具体的类实例。一定要注意,虽然前面的示例是利用简单工厂来创建的接口,但是也是可以用简单工厂来创建抽象类或者是普通类的实例的。
使用简单工厂的时候,通常不用创建简单工厂类的类实例,没有创建实例的必要。因此可以把简单工厂类实现成一个工具类,直接使用静态方法就可以了,也就是说简单工厂的方法通常都是静态的,所以也被称为静态工厂。如果要防止客户端无谓的创造简单工厂实例,还可以把简单工厂的构造方法私有化了。
一个简单工厂可以包含很多用来构造东西的方法,这些方法可以创造不同的接口、抽象类或者是类实例,一个简单工厂理论上可以构造任何东西,所以又称之为“万能工厂”。
虽然上面的实例中,在简单工厂里面只有一个方法,但事实上,是可以有很多这样创建方法的,这点要注意。
简单工厂创建对象的范围
虽然从理论上讲,简单工厂什么都能造,但对于简单工厂可创建对象的范围,通常不要太大,建议控制在一个独立的组件级别或者一个模块级别,也就是一个组件或模块一个简单工厂。否则这个简单工厂类会职责不明,有点大杂烩的感觉。
简单工厂的调用顺序示意图
简单工厂的调用顺序示意图
简单工厂命名的建议
类名建议为“模块名称+Factory”,比如:用户模块的工厂就称为:UserFactory
方法名称通常为“get+接口名称”或者是“create+接口名称”,比如:有一个接口名称为UserEbi,那么方法名称通常为:getUserEbi 或者是 createUserEbi。
当然,也有一些朋友习惯于把方法名称命名为“new+接口名称”,比如:newUserEbi,我们不是很建议。因为new在Java中代表特定的含义,而且通过简单工厂的方法来获取对象实例,并不一定每次都是要new一个新的实例。如果使用newUserEbi,这会给人错觉,好像每次都是new一个新的实例一样。
3.3 简单工厂中方法的写法
虽然说简单工厂的方法多是用来造接口的,但是仔细分析就会发现,真正能实现功能的是具体的实现类,这些实现类是已经做好的,并不是真的靠简单工厂来创造出来的,简单工厂的方法无外乎就是:实现了选择一个合适的实现类来使用。
所以简单工厂方法的内部主要实现的功能是“选择合适的实现类”来创建实例对象。既然要实现选择,那么就需要选择的条件或者是选择的参数,选择条件或者是参数的来源通常又有几种:
来源于客户端,由Client来传入参数
来源于配置文件,从配置文件获取用于判断的值
来源于程序运行期的某个值,比如从缓存中获取某个运行期的值
下面来看个示例,看看由客户端来传入参数,如何写简单工厂中的方法。
在刚才的示例上再添加一个实现,称为Impl2,示例代码如下:
* 对接口的一种实现
public class Impl2 implements Api{
public void test1(String s) {
System.out.println("Now In Impl The input s=="+s);
现在对Api这个接口,有了两种实现,那么工厂类该怎么办呢?到底如何选择呢?不可能两个同时使用吧,看看新的工厂类,示例代码如下:
* 工厂类,用来创造Api的
public class Factory {
* 具体的创造Api的方法,根据客户端的参数来创建接口
* @param type 客户端传入的选择创造接口的条件
* @return 创造好的Api对象
public static Api createApi(int type){
//这里的type也可以不由外部传入,而是直接读取配置文件来获取
//为了把注意力放在模式本身上,这里就不去写读取配置文件的代码了
//根据type来进行选择,当然这里的1和2应该做成常量
if(type==1){
api = new Impl();
}else if(type==2){
api = new Impl2();
客户端没有什么变化,只是在调用Factory的createApi方法的时候需要传入参数,示例代码如下:
public class Client {
public static void main(String[] args) {
//注意这里传递的参数,修改参数就可以修改行为,试试看吧
Api api = Factory.createApi(2);
api.test1("哈哈,不要紧张,只是个测试而已!");
要注意这种方法有一个缺点
由于是从客户端在调用工厂的时候,传入选择的参数,这就说明客户端必须知道每个参数的含义,也需要理解每个参数对应的功能处理。这就要求必须在一定程度上,向客户暴露一定的内部实现细节。
3.4 可配置的简单工厂
现在已经学会通过简单工厂来选择具体的实现类了,可是还有问题。比如:在现在的实现中,再新增加一种实现,会怎样呢?
那就需要修改工厂类,才能把新的实现添加到现有系统中。比如现在新加了一个实现Impl3,那么需要类似下面这样来修改工厂类:
public class Factory {
public static Api createApi(int type){
if(type==1){
api = new Impl();
}else if(type==2){
api = new Impl2();
}else if(type==3){
api = new Impl3();
每次新增加一个实现类都来修改工厂类的实现,肯定不是一个好的实现方式。那么现在希望新增加了实现类过后不修改工厂类,该怎么办呢?
一个解决的方法就是使用配置文件,当有了新的实现类过后,只要在配置文件里面配置上新的实现类就好了,在简单工厂的方法里面可以使用反射,当然也可以使用IoC/DI(控制反转/依赖注入,这个不在这里讨论)来实现。
看看如何使用反射加上配置文件,来实现添加新的实现类过后,无须修改代码,就能把这个新的实现类加入应用中。
配置文件用最简单的properties文件,实际开发中多是xml配置。定义一个名称为“FactoryTest.properties”的配置文件,放置到Factory同一个包下面,内容如下:
ImplClass=cn.javass.dp.simplefactory.example5.Impl
如果新添加了实现类,修改这里的配置就可以了,就不需要修改程序了。
此时的工厂类实现如下:
* 工厂类,用来创造Api对象
public class Factory {
* 具体的创造Api的方法,根据配置文件的参数来创建接口
* @return 创造好的Api对象
public static Api createApi(){
//直接读取配置文件来获取需要创建实例的类
//至于如何读取Properties,还有如何反射这里就不解释了
Properties p = new Properties();
InputStream in =
in = Factory.class.getResourceAsStream("FactoryTest.properties");
p.load(in);
} catch (IOException e) {
System.out.println("装载工厂配置文件出错了,具体的堆栈信息如下:");
e.printStackTrace();
in.close();
} catch (IOException e) {
e.printStackTrace();
//用反射去创建,那些例外处理等完善的工作这里就不做了
api = (Api)Class.forName(p.getProperty("ImplClass")).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
此时的客户端就变得很简单了,不再需要传入参数,代码示例如下:
public class Client {
public static void main(String[] args) {
Api api = Factory.createApi();
api.test1("哈哈,不要紧张,只是个测试而已!");
3.5 简单工厂的优缺点
帮助封装:简单工厂虽然很简单,但是非常友好的帮助我们实现了组件的封装,然后让组件外部能真正面向接口编程。
解耦:通过简单工厂,实现了客户端和具体实现类的解耦。如同上面的例子,客户端根本就不知道具体是由谁来实现,也不知道具体是如何实现的,客户端只是通过工厂获取它需要的接口对象。
可能增加客户端的复杂度:如果通过客户端的参数来选择具体的实现类,那么就必须让客户端能理解各个参数所代表的具体功能和含义,这会增加客户端使用的难度,也部分暴露了内部实现,这种情况可以选用可配置的方式来实现。
不方便扩展子工厂:私有化简单工厂的构造方法,使用静态方法来创建接口,也就不能通过写简单工厂类的子类来改变创建接口的方法的行为了。不过,通常情况下是不需要为简单工厂创建子类的。
3.6 思考简单工厂
简单工厂的本质
简单工厂的本质是:选择实现。
注意简单工厂的重点在选择,实现是已经做好了的。就算实现再简单,也要由具体的实现类来实现,而不是在简单工厂里面来实现。简单工厂的目的在于为客户端来选择相应的实现,从而使得客户端和实现之间解耦,这样一来,具体实现发生了变化,就不用变动客户端了,这个变化会被简单工厂吸收和屏蔽掉。
实现简单工厂的难点就在于“如何选择”实现,前面讲到了几种传递参数的方法,那都是静态的参数,还可以实现成为动态的参数。比如:在运行期间,由工厂去读取某个内存的值,或者是去读取数据库中的值,然后根据这个值来选择具体的实现等等。
何时选用简单工厂
建议在如下情况中,选用简单工厂:
如果想要完全封装隔离具体实现,让外部只能通过接口来操作封装体,那么可以选用简单工厂,让客户端通过工厂来获取相应的接口,而无需关心具体实现;
如果想要把对外创建对象的职责集中管理和控制,可以选用简单工厂,一个简单工厂可以创建很多的、不相关的对象,可以把对外创建对象的职责集中到一个简单工厂来,从而实现集中管理和控制。
3.7 相关模式
简单工厂和抽象工厂模式
简单工厂是用来选择实现的,可以选择任意接口的实现,一个简单工厂可以有多个用于选择并创建对象的方法,多个方法创建的对象可以有关系也可以没有关系。
抽象工厂模式是用来选择产品簇的实现的,也就是说一般抽象工厂里面有多个用于选择并创建对象的方法,但是这些方法所创建的对象之间通常是有关系的,这些被创建的对象通常是构成一个产品簇所需要的部件对象。
所以从某种意义上来说,简单工厂和抽象工厂是类似的,如果抽象工厂退化成为只有一个实现,不分层次,那么就相当于简单工厂了。
简单工厂和工厂方法模式
简单工厂和工厂方法模式也是非常类似的。工厂方法的本质也是用来选择实现的,跟简单工厂的区别在于工厂方法是把选择具体实现的功能延迟到子类去实现。如果把工厂方法中选择的实现放到父类直接实现,那就等同于简单工厂。
简单工厂和能创建对象实例的模式
简单工厂的本质是选择实现,所以它可以跟其它任何能够具体的创建对象实例的模式配合使用,比如:单例模式、原型模式、生成器模式等等。
做一个比较注重实际工作的有用的人

我要回帖

更多关于 小米售后检测要钱吗 的文章

 

随机推荐