java与模式笔记整理.docx
- 文档编号:7315288
- 上传时间:2023-01-22
- 格式:DOCX
- 页数:33
- 大小:46.79KB
java与模式笔记整理.docx
《java与模式笔记整理.docx》由会员分享,可在线阅读,更多相关《java与模式笔记整理.docx(33页珍藏版)》请在冰豆网上搜索。
java与模式笔记整理
JAVA与模式
里氏代换要求凡是基类型使用的地方,子类型一定适用,因此子类必须具备基类型的全部接口。
开-闭原则讲的是:
一个软件实体应当对扩展开放,对修改关闭。
在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。
换言之,应当可以在不必修改源代码的情况下改变这个模块的行为。
实现“开-闭”原则的关键是抽象化,并且从抽象化导出具体化实现。
信赖倒转原则要求客户端信赖于抽象耦合。
抽象不应当信赖于细节:
细节应当信赖于抽象。
要针对接口编程,不要针对实现编程。
接口隔离原则讲的是:
使用多个专门的接口比使用单一的总接口要好。
换言之,从一个客户类的角度来讲:
一个类对另外一个类的信赖性应当是建立在最小的接口上。
抽象类仅提供一个类型的部分实现。
具体类不是用来继承的,抽象类应当拥有尽可能多的共同代码。
抽象类应当拥有尽可能少的数据。
Java接口是一些方法特征的集合,这些方法特征当然来自于具体方法,但是它们一般都是来自于一些在系统中不断出现的方法。
接口是对可插入性的保证。
迪米特法则又叫做最少知识原则,就是说,一个对象应当对其他对象有尽可能少的了解。
代表性的描述:
只与你直接的朋友们通信。
不要跟“陌生人”说话。
每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
狭义的迪米特法则,如果其中的一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
但它会产生一个明显的缺点:
会在系统里选出大量的小方法,散落在系统的各个角落。
迪米特法则所谈论的,就是对对象之间的信息流量、流向以及信息的影响的控制。
在软件系统中,一个模块设计得好不好的最主要、最重要的标志,就是该模块在多大的程度上将自已的内部数据和其他与实现有关的细节隐藏起来。
或叫做“封装”。
信息的隐藏非常重要的原因在于,它可以使各个子系统之间脱耦,从而允许它们独立地被开发、优化、使用、阅读以及修改。
这种脱耦化可以有效地加快系统的开发过程,因为可以独立地同时开发各个模块。
它可以使维护过程变得容易,因为所有的模块都是容易读懂,特别是不必担心对其他模块的影响。
迪米特法则的主要用意是控制信息的过载。
要注意以下几点:
在类的划分上,应当创建有弱耦合的类。
在类的结构设计上,每一个类都应当尽量降低成员的访问权限。
在类的设计上,只要有可能,一个类应当设计成不变类。
在对其他类的引用上,一个对象对其对象的引用应当降到最低。
创建模式是对类的实例化过程的抽象化。
创建模式分为类的创建模式和对象的创建模式两种。
类的创建模式类的创建模式使用继承关系,把类的创建延迟到子类,从而封装了客户端将得到哪些具体类的信息,并且隐藏了这些类的实例是如何被创建和放在一起的。
对象的创建模式而对象的创建模式则把对象的创建过程动态地委派给另一个对象,从而动态地决定客户端将得到哪些具体类的实例,以及这些类的实例是如何被创建和组合在一起的。
简单工厂模式是类的创建模式,又叫做静态工厂方法模式。
简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
分为简单工厂模式又称静态工厂方法模式、工厂方法模式又称多态性工厂模式或虚拟构造子模式,抽象工厂模式又称工具箱模式。
包括单例模式,多例模式
工厂方法模式和简单工厂模式在结构上的不同是很明显的。
工厂方法模式的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。
工厂方法模式可以允许很多具体工厂类从抽象工厂类中将创建行为继承下来,从而可以成为多个简单工厂模式的综合,进而推广了简单工厂模式。
工厂方法模式后可以变得很像简单工厂模式。
抽象工厂角色可以规定多于一个的工厂方法,从而使具体工厂角色实现这些不同的工厂方法。
这些方法可以提供不同的商业逻辑,以满足提供不同的产品对象的任务。
抽象工厂模式:
一个系统不应当信赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
什么情况下应用?
这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不信赖于实现。
综合起来,抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,而不能为新的新品等级结构的增加提供这样的方便。
单例模式的特点:
单例类只能有一个实例,单例类必须自已创建自已的惟一的实例,单例类必须给所有其他对象提供这一实例。
饿汉式例类:
publicclassEagerSingleton
{
privatestaticfinalEagerSingletonm_instance=newEagerSingleton();
privateEagerSingleton(){}
publicstaticEagerSingletongetInstance()
{
returnm_instance;
}
}
懒汉式单例类:
publicclassLazySingleton
{
privatestaticLazySingletonm_instance=null;
privateLazySingleton(){}
synchronizedpublicstaticLazySingletongetInstance()
{
if(m_instance==null)
{
m_instance=newLazySingleton();
}
returnm_instance;
}
}
登记式单例类:
可以继承的单例类
publiccalssRegSingleton
{
staticprivateHashMapm_registry=newHashMap();
static
{
RegSingletonx=newRegSingleton();
m_registry.put(x.getClass().getName(),x);
}
protectedRegSingleton(){}
staticpublicRegSingletongetInstance(Stringname)
{
if(name==null)
{
name="RegSingleton";
}
if(m_registry.get(name)==null)
{
try
{
m_registry.put(name,Class.forName(name).newInstance());
}
catch(Exceptione)
{
System.out.println("Errorhappened.");
}
}
return(RegSingleton)(m_registry.get(name));
}
publicStringabout()
{
return"Hello,IamRegSingleton.";
}
}
子类:
publicclassRegSingletonChildextendsRegSingleton
{
publicRegSingletonChild(){}
staticpublicRegSingletonChildgetInstance
{
return(RegSingletonChild)RegSingleton.getInstance("RegSingletonChild");
}
publicStringabout()
{
return"Hello,IamRegSingletonChild.";
}
}
使用单例模式有一个必要条件:
在一个系统要求一个类只有一个实例时才应当使用单例模式。
反过来说,如果一个类可以有几个实例共存,那么就没有必要使用单例类。
有状态单例类
一个单例类可以是有状态的,一个有状态的单例对象一般也是可变单例对象。
有状态的可变的单例对象常常当做状态库使用。
比如一个单例对象可以持有一个int类型的属性,用来给一个系统提供一个数值惟一的序列号码,作为某个贩卖系统的账单号码。
当然,一个单例类可以持有一个聚集,从而允许存储多个状态。
无状态的单例类仅用做提供工具性函数的对象。
单例类局限于某一个JVM中,EJB跨过JVM后仍然需要引用同一个单例类的话,这个单例类就会在数个JVM中被实例化,造成多个单例对象的实例出现。
在任何使用了EJB、RMI和JINI技术的分散式系统中,应当避免使用有状态的单例模式。
同一个JVM中会有多个类加载器,当两个类加载器同时加载同一个类时,会出现两个实例。
很多J2EE服务器允许同一个服务器内有几个Servlet引擎时,每一个引擎都有独立的类加载器,经由不同的类加载器加载的对象之间是绝缘的。
分散系统中使用单例模式,尽量不要使用有状态的。
成例是一种代码层次上的模式,是在比设计模式的层次更具体的层次上的代码技巧,成例往往与编程语言密切相关。
建造械是对象的创建模式。
建造模式可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。
一个产品常有不同的组成成分作为产品的零件,这些零件有可能是对象,也有可能不是对象,它们通常又叫做产品的内部表象。
不同的产品可以有不同的内部表象,也就是不同的零件。
使用建造模式可以使客户端不需要知道所生成的产品对象有哪些零件,每个产品的对应零件彼此有何不同,是怎么建造出来的,以及怎样组成产品。
客户端负责创建导演者和具体建造者对象。
然后,客户把具体建造者对象交给导演者。
客户一声令下,导演者操纵具体建造者,开始创建产品。
具体建造者每接到导演者的一个指令,便按照指令向产品上增加一个构件。
当产品完成后,建造者把产品返还给客户端。
虽然客户端确实是具体建造者对象,但是操纵具体建造者的任务云阳属于导演者对象的。
把创建具体建造者对象的任务交给客户端而不是导演者对象,是为了将导演者对象与具体建造者对象的耦合变成动态的,从而使导演者对象可以操纵数个具体建造者对象中的任何一个。
所谓的多例模式,实际上就是对单例模式的自然推广。
多例类可有多个实例,多例类必须自已创建、管理自已的实例,并向外界提供自已的实例。
一个有上限的多例类可以使用静态变量存储所有的实例,特别是在实例数目不多的时候,可以使用一个个的静态变量存储一个个的实例。
在数目较多的时候,就需要使用静态聚集存储这些实例。
实例数目没有上限的多例模式就叫做无上限多例模式。
在很多情况下,建造模式实际上是将一个对象的性质建造过程外部化到独立的建造者对象中,并通过一个导演者角色对这些外部化的性质赋值过程进行协调。
在以下情况下应当使用建造模式:
需要生成的产品对象有复杂的内部结构。
每一个内部成分本身可以是对象,也可以仅仅是一个对象的一个组成成分。
需要生成的产品对象的属性相互信赖。
建造模式可以强制实行一种分步骤进行的建造过程。
在对象创建过程中会使用到系统中的其他一些对象,这些对象在产品对象的创建过程中不易得到。
建造模式的使用使得产品的内部表象可以独立地变化。
使用建造模式可以使客户端不必知道产品内部组成的细节。
每一个Builder都相对独立,而与其他的Builder无关。
模式所建造的最终产品更易于控制。
在抽象工厂模式中,每一次工厂对象被调用时都会返还一个完整的产品对象,而客户端有可能会决定把这些产品组装成一个更大更复杂的产品,也有可能不会。
建造类则不同,它一点一点地建造出一个复杂的产品,而这个产品的组装就发生在建造者角色内部。
建造者模式的客户端拿到的是一个完整的最后产品。
准备一个抽象类,将部分逻辑以具体方法以及具体构造子的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。
建造模式与策略模式的区别
建造模式在结构上很接近于策略模式,事实上建造模式是策略模式的一种特殊情况,这两种模式的区别在于它们的用意不同。
建造模式适用于客户端一点一点地建造新的对象,而不同类型的具体建造者角色虽然都拥有相同的接口,但是它们所创建出来的对象则可能完全不同。
策略模式的目的是为算法提供抽象的接口。
换言之,一个具体策略类把一个算法包装到一个对象里面,而不同的具体要求策略对象为一种一般性的服务提供不同的实现。
原始模型模式
原始模型模式属于对象的创建模式。
通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。
克隆满足的条件
对任何的对象x,都有:
x.clone()!
=x。
换言之,克隆对象与原对象不是同一个对象。
对任何的对象x,都有:
x.clone().getClass==x.getClass(),换言之,克隆对象与原对象的类型一样。
如果对象的x的equals()方法定义恰当的话,那么x.clone().equals(x)应当是成立的。
原始模型模式有两种表现形式:
第一种是简单形式:
如果需要创建的原型对象数目较少而且比较固定的话。
第二种是登记形式:
如果要创建的原型对象数目不固定的话。
浅复制:
浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
深复制:
深复制把要复制的对象所引用的对象都复制了一遍,而这种对被引用到的对象的复制叫做间接复制。
利用串行化来做深复制
publicObjectdeepClone()
{
ByteArrayOutputStreambo=newByteArrayOutputStream();
ObjectOutputStreamoo=newObjectOutputStream(bo);
oo.writeObject(this);
ByteArrayInputStreambi=newByteArrayInputStream(bo.toByteArray());
ObjectInputStreamoi=newObjectInputStream(bi);
return(oi.readObject());
}
这样做的前提就是对象以及对象内部所有引用到的对象都是可串行化,否则就需要仔细考察那些不可串行化的对象可否设成transient,从而将之排除在复制过程之外。
有一些对象,比如线程(thread)对象或Socket对象,是不能简单复制对象或共享的。
不管是使用深复制还是浅复制,只要涉及这样的间接对象,就必须把间接对象设成transient而不予复制;或者由程序自行创建出相当的同种对象,权且当做复制件使用。
原始模型模式允许动态地增或减少产品类。
原始模型模式提供简化的创建结构。
具有给一个应用软件动态加载新功能的能力。
产品类不需要非得有任何事先确定的等级结构,因为原始模型模式适用于任何的等级结构。
原始模型模式经常与合成模式一同使用,因为原型对象经常是合成对象。
串行化(Serialization)使得一个程序可以把一个完整的对象写到一个Byte流里面,或者从一个Byte流里面读出一个事先存储在里面的完整的对象;串行化可以把Java对象和原始数据类型转换成一个适合于某种网络或文件系统的Byte流。
串行处理功能真正强大之处在于一个Java程序不需要直接处理存储在硬盘上面的原始数据,就可以很容易地将一个Java对象和一个二进制流之间相互转换。
将一个Java对象串行化只需要实现两个接口中的一个即可:
要么实现java.io.Serializable接口,要么实现Externalizable接口。
Serializable接口是一个标识接口,也就是说它是一个没有方法的接口。
Externalizable接口是一个有两个方法的Serializable接口的子接口,因此实现这个接口的类必须实现这两个方法。
java.lang.Throwable类实现了Serializable接口,因此所有的Exception和Error类均是可以串行化的。
而流、所有的Reader和Writer以及其他的I/O类均是不可以串行化的;AWT和Swing、容器类、事件类均是可以串行化的;事件适配器类、图像过滤器类、AWT包中与操作系统相关的特性类均是不可以串行化的;原始类型的封装类中只有Void类是可以串行化的;多数的java.lang包中的类是不可以串行化的;反射(Reflection)类是不可以说串行化的;java.math中的类都是可以串行化的;压缩类都是不可以串行化的。
满足下面的四个条件之一的类就不应当串行化:
1、一个类与本地代码(nativecode)有紧密的关系。
比如java.util.zip.Deflater就是一个例子。
2、对象的内部状态信赖于Java虚拟机或运行环境,从而在每一次运行时这个状态有可能不同。
比如java.lang.Thread,java.io.InputStream,java.io.FileDescriptor,java.awt.PrintJob等。
3、串行化可能带来潜在的安全隐患。
比如,java.lang.SecurityManager以及java.security.MessageDigest等。
4、一个类仅仅是一些静态方法的存放地,并没有任何的内部状态。
比如,java.beans.Beans和java.lang.Math便是此类。
结构模式描述如何将类或者对象结合在一起形成更大的结构。
结构模式描述两种不同的东西:
类与灰的实例。
类的结构模式类的结构模式使用继承来把类、接口等组合在一起,以形成更大的结构。
当一个类从父类继承并实现某接口时,这个新的类就把父类的结构和接口的结构结合起来,类的结构模式是静态的。
一个类的结构模式的典型例子,就是类形式的适配器模式。
对象的结构模式对象的结构模式描述怎样把各种不同类型的对象组合在一起,以实现新的功能的方法。
对象的结构模式是动态的。
适配器模式
适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
像变压器,变压器把一种电压变换成另一种电压,此模式也常常被称为变压器模式。
也很像货物的包装过程:
被包装的货物的真实样子被所掩盖和改变,因此有人把这种模式叫做包装(Wrapper)模式。
大家经常写很多这样的Wrapper类,把已有的一些类包装起来,使之能有满足需要的接口。
适配器模式有类的适配器模式和对象的适配器模式。
与类的适配器模式一样,对象的适配器模式把被适配的类的API转换成目标类的API,与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类。
适配器模式的用意是将接口不同而功能相同或者相近的两个接口加以转换。
对象的适配器模式的效果:
1、一个适配器可以把多种不同的源适配到同一个目标,换言之,同一个适配器可以把源类和它的子类都适配到目标接口。
与类的适配器模式相比,要想置换源类的方法就不容易。
虽然要想置换源类的方法不容易,但是要想增加一些新方法则方便得很,而且新增加的方法可同时适用于所有的源。
在以下各种情况下使用适配器模式:
1、系统需要使用现有的类,而此类的接口不符合系统的类型。
想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
这些源类不一定有很复杂的接口。
在设计里,需要改变多个已有的子类的接口,如果使用类的适配器模式,就要针对每一个子类做一个适配器类,而这不太实际。
适配器模式可以在架构层次上使用。
目标接口可以省略。
适配器可以是抽象类。
带参数的适配器模式。
缺省适配模式为一个接口提供缺省实现,这样子类型可以从这个缺省实现进行扩展,而不必从原有接口进行扩展。
它是为了方便建立一个不平庸的适配器类而提供的一种平庸实现。
可以使所考察的类不必实现不需要的那部分接口。
缺省适配器模式的中心是一个缺省适配器类。
这个类应当是抽象类,因为这个类不应当实例化,它的实例也没有用处。
但是缺省适配器类所提供的方法却应当是具体的方法,而不是抽象的方法,因为按照模式的用意,这些方法之所以存在,就是为了提供默认实现,以便缺省的具体子类可以按照需要需要实现的方法,忽略不需要实现的方法。
DOM是文本驱动,SAX是事件驱动的。
合成模型模式属于对象的结构模式,有时又叫做部分-整体模式。
合成模式将对对象组织到树结构中,可以用来描述整体与部分的关系。
合成模式可以使客户端将单纯元素与复合元素同等看待。
一个基于继承的类型的等级结构便是一个树结构;一个基于合成的对象结构也是一个树结构。
合成模式的实现根据所实现接口的区别分为两种形式,分别称为安全式(树叶类和合成类对象有相同的接口层次)和透明式(树叶类和合成类将具有不同的接口)。
明显地给出父对象的引用。
应用安全式合成模式:
安全形式的合成模式意味着只有树枝构件角色才配备有管理聚集的方法,而树叶构件则没有这些方法。
在下面的情况下应当考虑使用合成模式:
需要描述对象的部分和整体的等级结构。
需要客户端忽略掉个体构件和组合构件的区别。
客户端必须平等对待所有的结构件,包括个体构件和组成构件。
合成模式优点:
合成模式可以很容易地增加新各类的构件。
使用合成模式可以使客户端变得很容易设计,因为客户端不需要知道构件是树叶构件还是树枝构件。
合成模式缺点:
使用合成模式后,控制树枝构件的类型就不太容易。
用继承的方法来增加新的行为很困难。
装饰模式又名包装模式。
装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任。
换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。
装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。
在以下情况应当使用装饰模式:
1、需要扩展一个类的功能,或给一个类增加附加责任。
2、需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
3、需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。
使用装饰模式主要有以下的优点:
1、装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。
2、通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
3、这种比继承更加机动的特性,也同时意味着装饰模式比更加易于出错。
缺点:
由于使用装饰模式,可以比使用继承关系需要较少数目的类。
使用较少的类,当然使设计比较易于进行。
但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。
更多的对象使得查错变得困难,特别是这些对象看上去都很相像。
模式简化时要注意:
一个装饰类的接口必须与被装饰类的接口相容。
尽量保值Component作为一个“轻”类。
如果只有一个ConcreteComponent类而没有抽象的Component类(接口),那么Decorator类经常可以是ConcreteComponent的一个子类。
如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator的责任合并成一个类。
甚至在只有两个ConcreteDecorator类的情况下,都可以这样做。
但如果大于三的话,使用一个单独的Decorator类来区分抽象和具体的责任就是必要的了。
半透明的装饰模式是介于装饰模式和适配器模式之间的。
装饰模式和适配器械都包装模式
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- java 模式 笔记 整理