Java与模式
1工厂模式专门负责将大量有共同接口的类实例化。工厂模式可以动态决定将哪一个类
实例化,不必事先知道每次要实例化哪一个类。工厂模式有以下几种形态:
(1)简单工厂(Simple Factory)模式,又称静态工厂方法模式(Static Factory Method Pattern)。
(2)工厂方法(Factory Method)模式,又称多态性工厂(Polymorphic Factory)模式或虚拟构造子(Virtual Constructor模式;
(3)抽象工厂(Abstract Factory)模式,又称工具箱(Kit 或Toolkit)模式。
1)简单工厂(Simple Factory)模式 ,简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。
简单工厂的结构 |
简单工厂模式是由一个工厂对象决定创建出那一种产品类的实例。其实简单工厂模式就是由一个工厂类可以根据传入的参量决定创建出哪一种产品类的实例
实例:有三种水果,他们的父接口就是fruit
葡萄 Grape
草莓 Strawberry
苹果 Apple
public class FruitGardener
{
/**
* 静态工厂方法
*/
public static Fruit factory(String which) throws BadFruitException
{ if (which.equalsIgnoreCase("apple")){
return new Apple();
}
else if (which.equalsIgnoreCase("strawberry")){
return new Strawberry();
}
else if (which.equalsIgnoreCase("grape")){
return new Grape();
} else{ throw new BadFruitException("Bad fruit request");
}
}
}
在使用时,客户端只需调用FruitGardener 的静态方法factory()即可
2)工厂方法(Factory Method)模式工厂方法模式是类的创建模式,又叫做虚拟构造子(Virtual Constructor)模式或者多
态性工厂(Polymorphic Factory)模式。工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子
类中。工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点[U1]
首先,在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。这个核心类则摇身一变,成为了一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。这种进一步抽象化的结果,使这种工厂方法模式可以用来允许系统在不修改具体工厂角色的情况下引进新的产品,这一特点无疑使得工厂模式具有超过简单工厂模式的优越性。
1:抽象工厂角色Creator 类的源代码
package com.javapatterns.factorymethod;
public interface Creator{
/*** 工厂方法*/
public Product factory();
}
抽象产品角色Product 类的源代码
package com.javapatterns.factorymethod;
public interface Product
{
}
3:具体工厂角色ConcreteCreator1 类的源代码
package com.javapatterns.factorymethod;
public class ConcreteCreator1 implements Creator
{
/*** 工厂方法*/
public Product factory(){
return new ConcreteProduct1();
}
}
具体工厂角色ConcreteCreator2 类的源代码
package com.javapatterns.factorymethod;
public class ConcreteCreator2 implements Creator{
/*** 工厂方法*/
public Product factory(){
return new ConcreteProduct2();
}
}
具体产品角色ConcreteProduct1 类的源代码
package com.javapatterns.factorymethod;
public class ConcreteProduct1 implements Product{
public ConcreteProduct1(){
//do something
}
}
具体产品角色ConcreteProduct2 类的源代码
package com.javapatterns.factorymethod;
public class ConcreteProduct2 implements Product{
public ConcreteProduct2(){
//do something
}
}
客户端角色Client 类的源代码
package com.javapatterns.factorymethod;
public class Client{
private static Creator creator1, creator2;
private static Product prod1, prod2;
public static void main(String[] args) {
creator1 = new ConcreteCreator1();
prod1 = creator1.factory();
creator2 = new ConcreteCreator2();
prod2 = creator2.factory();
}
}
注意:工厂方法模式在农场系统中的实现图
3)抽象工厂(Abstract Factory)模式抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。它是工厂方法模式的进一步推广。抽象工厂模式的简略类图如下所示。
★左边的等级结构代表工厂等级结构,右边的两个等级结构分别代表两个不同的产品的
等级结构。抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的
具体类型的情况下,创建多个产品族中的产品对象。这就是抽象工厂模式的用意。
实例
源代码
下面给出这个系统所有的源代码。
首先给出工厂角色的源代码,可以看出,抽象工厂角色规定出两个工厂方法,分别提供两个不同等级结构的产品对象。
代码清单1:抽象产品角色的源代
package com.javapatterns.abstractfactory;
public interface Creator{
/**
* 产品等级结构A 的工厂方法
*/
public ProductA factoryA();
/**
* 产品等级结构B 的工厂方法
*/
public ProductB factoryB();
}
具体工厂类ConcreteCreator1 的源代码
package com.javapatterns.abstractfactory;
public class ConcreteCreator1 implements Creator
{
/**
* 产品等级结构A 的工厂方法
*/
public ProductA factoryA(){
return new ProductA1();
}
/**
* 产品等级结构B 的工厂方法
*/
public ProductB factoryB(){
return new ProductB1();
}
}
代码清单3:具体工厂类ConcreteCreator2 的源代码
package com.javapatterns.abstractfactory;
public class ConcreteCreator2 implements Creator{
/**
* 产品等级结构A 的工厂方法
*/
public ProductA factoryA(){
return new ProductA1();
}
/**
* 产品等级结构B 的工厂方法
*/
public ProductB factoryB(){
return new ProductB1();
}
}
代码清单4:具体产品类ProductA 的源代码
package com.javapatterns.abstractfactory;
public interface ProductA
{
}
代码清单5:具体产品类ProductA1 的源代码
package com.javapatterns.abstractfactory;
public class ProductA1 implements ProductA{
public ProductA1(){}
}
代码清单6:具体产品类ProductA2 的源代码
package com.javapatterns.abstractfactory;
public class ProductA2 implements ProductA{
public ProductA2(){ }
}
代码清单7:抽象产品角色ProductB 的源代码
package com.javapatterns.abstractfactory;
public interface ProductB{
}
代码清单8:具体产品类ProductB1 的源代码
package com.javapatterns.abstractfactory;
public class ProductB1 implements ProductB{
/*** 构造子*/
public ProductB1(){ }
}
代码清单9:具体产品类ProductB2 的源代码
package com.javapatterns.abstractfactory;
public class ProductB2 implements ProductB{
/*** 构造子*/
public ProductB2(){}
}
工厂模式的相关应用:
★spring中的大量使用工厂模式。
★在SAX2 库中,XMLReaderFactory 类使用了简单工厂模式,用来创建产品类XMLReader 的实例。
★用工具类java.text.DateFormat 或其子类来格式化一个本地日期或者时间
★Java 集合是Java 1.2 版提出来的。多个对象聚在一起形成的总体称之为集合(Aggregate),集合对象是能够包容一组对象的容器对象。所有的Java 集合都实现java.util.Collection 接口,这个接口规定所有的Java 聚集必须提供一个iterator()方法,返还一个Iterator 类型的对象一 个具体的Java 聚集对象会通过这个iterator()方法接口返还一个具体的Iterator 类。可以看出,这个iterator()方法就是一个工厂方法。
★在微软公司所提倡的COM(Component Object Model)技术架构中, 工厂方法模式起着关键的作用。
★在EJB 技术架构中,工厂方法模式也起着关键的作用
★JMS(Java Messaging Service) 技术架构中的工厂方法模式
2,单例(Singleton)模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。单例模式有以下三个的特点:
? ★ 单例类只可有一个实例。
? ★单例类必须自己创建自己这惟一的实例。
? ★ 单例类必须给所有其他对象提供这一实例。
注意:虽然单例模式中的单例类被限定只能有一个实例,但是单例模式和单例类可以很容易被推广到任意且有限多个实例的情况,这时候称它为多例模式(Multiton Pattern)和多例类(Multiton Class),
一个例子:Windows 回收站
在整个视窗系统中,回收站只能有一个实例,整个系统都使用这个惟一的实例,而且
回收站自行提供自己的实例。因此,回收站是单例模式的应用。
单列模式的实现主要有两种:饿汉式单例类和懒汉式单例类
1)饿汉式单例类
代码清单1:饿汉式单例类
public class EagerSingleton{
private static final EagerSingleton m_instance = new EagerSingleton();
/*** 私有的默认构造子*/
private EagerSingleton() { }
/*** 静态工厂方法*/
public static EagerSingleton getInstance(){
return m_instance;
}
}
读者可以看出,在这个类被加载时,静态变量m_instance 会被初始化,此时类的私有
构造子会被调用。这时候,单例类的惟一实例就被创建出来了。
Java 语言中单例类的一个最重要的特点是类的构造子是私有的,从而避免外界利用构
造子直接创建出任意多的实例。值得指出的是,由于构造子是私有的,因此,此类不能被
继承。
2)懒汉式单例类。与饿汉式单例类相同之处是,类的构造子是私有的。与饿汉式单例类不同的是,懒汉
式单例类在第一次被引用时将自己实例化。如果加载器是静态的,那么在懒汉式单例类被
加载时不会将自己实例化
代码清单2:懒汉式单例类
package com.javapatterns.singleton.demos;
public class LazySingleton{
private static LazySingleton m_instance = null; 加载时并不创建对象,而是在需要的时候在创建
/**
* 私有的默认构造子,保证外界无法直接实例化
*/
private LazySingleton() { }
/*** 静态工厂方法,返还此类的惟一实例*/
synchronized public static LazySingleton
getInstance(){
if (m_instance == null)
{ m_instance = new LazySingleton();
}
return m_instance;
}
}
读者可能会注意到,在上面给出懒汉式单例类实现里对静态工厂方法使用了同步化,
以处理多线程环境。有些设计师在这里建议使用所谓的“双重检查成例”。必须指出的是,
“双重检查成例”不可以在Java 语言中使用。
3)登记式单例类
登记式单例类是GoF 为了克服饿汉式单例类及懒汉式单例类均不可继承的缺点而设计的
这样做的缺点
由于子类必须允许父类以构造子调用产生实例,因此,它的构造子必须是公开的。
这样一来,就等于允许了以这样方式产生实例而不在父类的登记中。
这是登记式单例类的一个缺点。
GoF 曾指出,由于父类的实例必须存在才可能有子类的实例,这在有些情况下是一个
浪费。 这是登记式单例类的另一个缺点。
3,多例模式
所谓的多例模式(Multiton Pattern),实际上就是单例模式的自然推广。作为对象的创
建模式,多例模式或多例类有以下的特点:
(1)多例类可有多个实例。
(2)多例类必须自己创建、管理自己的实例,并向外界提供自己的实例。
1)有上限多例模式。一个实例数目有上限的多例类已经把实例的上限当做逻辑的一部分,并建造到了多例
类的内部,这种多例模式叫做有上限多例模式。
比如每一麻将牌局都需要两个色子,因此色子就应当是双态类。这里就以这个系统为
例,说明多例模式的结构。色子的类图如下所示。
下面就是多例类Die(色子)的源代码。
代码清单3:多例类的源代码
package com.javapatterns.multilingual.dice;
import java.util.Random;
import java.util.Date;
public class Die{
private static Die die1 = new Die();
private static Die die2 = new Die();
/**
* 私有的构造子保证外界无法
* 直接将此类实例化
*/
private Die(){ }
/*** 工厂方法*/
public static Die getInstance(int whichOne) {
if (whichOne == 1) {
return die1;
}
else{
return die2;
}
}/*** 掷色子,返还一个在1~6 之间的* 随机数*/
public synchronized int dice(){
Date d = new Date();
Random r = new Random( d.getTime() );
int value = r.nextInt();
value = Math.abs(value);
value = value % 6;
value += 1;
return value;
}
}代码清单4:客户端的源代码
package com.javapatterns.multilingual.dice;
public class Client{
private static Die die1, die2;
public static void main(String[] args) {
die1 = Die.getInstance(1);
die2 = Die.getInstance(2);
die1.dice();
die2.dice();
}
}
2)无上限多例模式, 由于没有上限的多例类对实例的数目是没有限制的,因此,虽然这种多例模式是单例模式的推广,但是这种多例类并不一定能够回到单例类。
应用:序列键生成器与单例及多例模式
4,原始模式,通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。这就是原始模型模式的用意。Java语言的构件模型直接支持原始模型模式。所有的JavaBean都继承自java.lang.Object,而Object类提供一个clone()方法,可以将一个JavaBean对象复制一份;但是这个JavaBean必须实现一个标示接口Cloneable表明这个JavaBean支持复制。如果一个对象没有实现这个接口而调用clone()方法,Java编译器会抛出CloneNotSupportedException异常。
5建造模式,建造模式的定义为:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。可以将建造模式的精髓概括为:将构造复杂对象的过程和对象的部件解耦。这是对降低耦合、提高可复用性精神的一种贯彻。其实这种精神贯彻在GOF几乎所有的设计模式中。
2)各类的说明如下:
i)抽象建造者(Builder)角色:给出一个抽象接口,以规范产品对象的各个组成成分的构造;
ii)具体建造者(ConcretBuilder)角色:它在应用程序的调用下创建产品的实例。完成任务为;
a) 实现抽象建造者Builder接口,给出一步步完成创建产品实例的操作;
b) 在创建完成后,提供产品的实例。
iii) 导演者(Director角色):调用具体建造者角色以创建产品对象;
iv)产品(Product)角色:建造中的复杂对象。一般情况下,一个系统不止一个产品类。
Java中的应用:javamail中使用建造者模式
6,适配器模式
目的:将一个类的接口转换成客户希望的另外一个接口。A d a p t e r 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。适配器的两种模式:类的适配器模式和对象的适配器模式
1)类的适配器模式,类的适配器模式把适配的类的API转换成目标类的API。
目标(Target)角色:这就是所期待得到的接口。
源(Adaptee)角色:现有需要适配的接口。
适配器(Adapter)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。
显然这一角色不可以是接口,而必须是具体类。
/*** 定义Client使用的与特定领域相关的接口 */
public interface Target {
void sampleOperation1();
void sampleOperation2();
}
/*** 定义一个已经存在的接口,这个接口需要适配*/
public class Adaptee {
public void sampleOperation1() {
// ......
}
}
/*** 对Adaptee与Target接口进行适配*/
public class Adapter extends Adaptee implements Target {
public void sampleOperation2() {
// ......
}
}
2)对象的适配器,与类的适配器模式一样,对象适配器模式把适配的类的API
转换成为目标类的API,与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类。示意代码如下:
/** * 定义Client使用的与特定领域相关的接口*/
public interface Target {
void sampleOperation1();
void sampleOperation2();
}
/** * 定义一个已经存在的接口,这个接口需要适配*/
public class Adaptee {
public void sampleOperation1() {
// ......
}
}
/** * 对Adaptee与Target接口进行适配 */
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
super();
this.adaptee = adaptee;
}
public void sampleOperation1() {
adaptee.sampleOperation1();
}
public void sampleOperation2() {
// ......
}
}
类适配器模式和对象适配器模式的异同:Target接口和Adaptee类都相同,不同的是类适配器的Adapter继承Adaptee实现Target,对象适配器的Adapter实现Target聚集Adaptee。
应用:1JDBC驱动软件与适配器模式.JDBC给出一个客户端通用的界面,每个数据库引擎的JDBC驱动软件都是一个介于JDBC接口和数据库引擎接口之间的适配器软件
2 JDBC/ODBC如果没有合适的jdbc软件驱动,用户也可以用ODBC驱动软件把JDBC通过一个JDBC/ODBC桥梁软件与ODBC连接起来从而达到连接数据库的目的,JDBC的库不可能和ODBC的库有相同的接口,因此使用适配器模式将ODBC的api接口改为JDBC的接口,因此JDBC/ODBC桥梁是适配器模式的应用。
3,XMLProperties使用了适配器模式
- 观察者模式,观察者模式又叫作发布-订阅模式(publish-subscribe),模型-视图(model-view)模式,源-监听者(source-listener)模式,或者从属者(dependents)模观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生改变时,会通知所有的观察者对象,使他们能够自动更新自己。
这种观察模式在理解上相当于报社与订阅者之间的关系。出版者相当于“主题Subuject”,订阅者相当于“Observer”。主题对象管理某些数据,当主题内的数据改变时就会通知观察者,观察者(已经订阅的/ 注册了的)就会收到更新。
发布者叫事件源,订阅者叫事件监听器,在java里时间用类代表
java.util包内包含最基本的Observer接口与Observable类,如果使用该内置的支持,就只需要写一个类去扩展(继承)Observable,并告诉它何时该通知观察者, 一切就完成了,剩下的API会帮你做。你可以根据需要编写具体的观察者的类,在这个类中定义update()方法,去实现Observer接口。
public class Observable {
private boolean changed = false;
private Vector obs;
//创建被观察者时就创建一个它持有的观察者列表,
//注意,这个列表是需要同步的。
public Observable() {
obs = new Vector();
}
/** * 添加观察者到观察者列表中去*/
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
/** * 删除一个观察者 */
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
/** * 通知操作,即被观察者发生变化,通知对应的观察者进行事先设定的操作,不传参数的通知方法 */
public void notifyObservers() {
notifyObservers(null);
}
/** * 与上面的那个通知方法不同的是,这个方法接受一个参数,这个参数一直传到观察者里,以供观察者使用*/
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
}
public interface Observer {
void update(Observable o, Object arg);
}
}
这是一个接口,接口中就只有一个方法,update,方法中有两个参数,Observable和一个object,第一个参数就是被观察的对象,而第二个参数就得看业务需求了,需要什么就传进去什么。我们自己的观察者类必须实现这个方法,这样在被观察者调用notifyObservers操作时被观察者所持有的所有观察者都会执行update操作了(当然如果你override这个方法,你甚至可以指定何种情况下只执行某种observer了,是不是比较像责任链模式了)。
首先让我们来实现一个发送邮件的观察者:
Java代码
public class MailObserver implements Observer{
/** 这个类取名为MailObserver,顾名思义,她是一个用来发送邮件的观察者 */
public void update(Observable o, Object arg) {
System.out.println("发送邮件的观察者已经被执行");
}
}
接下来让我们再来实现被观察者,示例如下:
Java代码
public class Subject extends Observable{
/** * 业务方法,一旦执行某个操作,则通知观察者 */
public void doBusiness(){
if (true) {
super.setChanged();
}
notifyObservers("现在还没有的参数");
}
public static void main(String [] args) {
//创建一个被观察者
Subject subject = new Subject();
//创建两个观察者
Observer mailObserver = new MailObserver();
Observer jmsObserver = new JMSObserver();
//把两个观察者加到被观察者列表中
subject.addObserver(mailObserver);
subject.addObserver(jmsObserver);
//执行业务操作
subject.doBusiness();
}
}
观察者模式与AWT中的事件处理。Java1.0的事件处理机制是建立在责任链模式的基础之上的,但是这种不能满足打应用系统的需求,在java1.1后改为建立在观察者模式之上的以事件的委派为特征的委派事件模型(Delegation Event Model DEM),这种DEM的机制不仅在AWT中使用还在Swing中使用
在AWT中的观察者模式 DEM的结构(三要素)
1)事件源对象 ,一个类要成为事件源不需要实现任何接口和继承任何类,但是一个事件源要保持一个事件监听器的列表。调用 addXXXListener()方法增加一个监听器,调用removeXXXListener()方法删除一个监听器。不同的事件就要不同的监听器
2)事件对象,每一个事件都有一个事件对象与他对应,所有的AWT中的事件对象都是从java.util.EventObject继承而来的
常用的有ActionEvent MourseEvent
3)事件监听器对象,当事件发生时被调用的对象,一个对象要想成为一个事件监听对象,必须要实现事件监听接口,AWT中的事件接口都是java.util.EventListener
实例
import java.awt.Frame;
import java.awt.event.MouseListener;
public class ConcreteSubject extends Frame{
private static MouseListener m;
public ConcreteSubject(){}
public static void main(String[] argv)
{
ConcreteSubject s = new ConcreteSubject();
m = new ConcreteListener();
s.setBounds(100, 100, 100 , 100);
s.addMouseListener(m);
s.show();
}}
public class ConcreteListener
implements MouseListener{
ConcreteListener(){ }
public void mouseClicked(MouseEvent e) {
System.out.println(e.getWhen());
}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
}
- 代理模式
1)代理模式[U2] 的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。利用中间对象起到加强对象功能的模式还有,装饰模式,适配器模式
代理模式有以下几种:远程代理(EJB Spring的远程代理) 虚拟代理 保护代理 同步代理 防火墙代理 智能代理
抽象角色:声明真实对象和代理对象的共同接口;没有共同的接口那就是委托
2)代理模式的结构
abstract public class Subject{
abstract public void request();
}
package com.javapatterns.proxy;
public class RealSubject extends Subject {
public RealSubject(){ }
public void request(){
System.out.println("From real subject.");
}
}
public class ProxySubject extends Subject {
private RealSubject realSubject;
public ProxySubject(){}
public void request(){
preRequest();
if( realSubject == null ) {
realSubject = new RealSubject();
}
realSubject.request();
postRequest();
}
private void preRequest(){
//something you want to do before requesting
}
private void postRequest(){
//something you want to do after requesting
}
}
public class Client{
private static Subject subject;
static public void main(String[] args){
subject = new ProxySubject();
subject.request();
subject.request();
}
}
- 装饰模式又叫包装模式,装饰模式是对对象功能增强时,平时使用继承的一种替代方案
模式结构和代码
public interface Component{
void sampleOperation();
}
public class Decorator implements Component{
public Decorator(Component component){
// super();
this.component = component;
}
public Decorator() {}
public void sampleOperation(){
component.sampleOperation();
}
private Component component;
}
public class ConcreteComponent implements Component{
public void sampleOperation(){
// Write your code here
}
}
public class ConcreteDecorator extends Decorator{
public void sampleOperation() {
super.sampleOperation();
}
}
装饰模式的电信创建模式
new Decorator1(
new Decorator2(
new ConcreteComponent())); 所以装饰模式常常也叫包裹模式
注意: 1,InputStreamReader是把InputStream包装起来,把InputStreamReader的API转换成Reader的api,所以它是适配器模式,而不是桥梁模式。只是相当一个桥梁。
2,在java.io中的BufferedReader是一个装饰类,也可以看成半个适配器模式(因为它提供了一个readLine()新方法)一个装饰类实现的新方法越多,就离装饰类越远
3,在java.io中充满了装饰模式和适配器模式。
9,门面模式:外部与一个子系统的通信必须通过一个统一的门面对象进行,这就是门面模式。一般而言,Facade模式是为了降低子系统之间,客户端与实现化层之间的依赖性。当在构建一个层次化的系统时,也可以同过使用Facade模式定义系统中每一层的入口,从而简化层与层之间的依赖关系。
应用:struts的action就是相当一个门面,参考ejb java ee的结构
10,桥梁模式。桥梁模式的用意是把抽象化与实现化脱耦。脱耦是说把抽象和实现之间的耦合解脱,或者说把强关联变成弱关联。桥梁模式的脱耦指的就是把抽象和实现之间的继承/实现关系变成组合/聚合关系。从而可以使两者可以相对独立的变化。这就是桥梁模式的本意。
结构图如下
桥梁模式的关键是找出抽象化角色和具体化角色。典型应用是JDBC驱动器的应用。
11,不变模式
不变模式可增强对象的强壮性(robustness)。不变模式允许多个对象共享某一对象,降低对该对象进行并发访问的同步化开销。如果需要修改一个不变对象的状态,就需要建立一个新的同类型对象,并在创建时将这个新的状态存储在新对象里。
不变模式之设计一个类。一个类的内部状态创建后,在整个生命期内都不会发生变化时,这个类被称为不变类。这种使用不变类的做法叫作不便模式。
弱不变模式:一个类的实例状态不可改变,但是子类的实例具有可能会变化的状态。对象没有任何方法可以修改对象的状态 所有的属性都应该是私有的
强不变模式:一个类的实例不可改变,子类的实例也不可改变,满足弱不变模式还要满足
1类所有的方法都应当是final,这样这个类的子类不能够换掉此类的方法
2这个类本身就是final的,不存在子类
在java中的应用:最著名的就是String类,它是一个强不变类,
12,策略模式。策略模式(Strategy Pattern)中体现了两个非常基本的面向对象设计的基本原则:封装变化的概念;编程中使用接口,而不是对接口实现。策略模式的定义如下:
定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。策略模式使这些算法在客户端调用它们的时候能够互不影响地变化。
策略模式的好处在于你可以动态的改变对象的行为。
public class Context{
public void contextInterface(){
strategy.strategyInterface();
}
private Strategy strategy;
}
abstract public class Strategy{
public abstract void strategyInterface();
}
public class ConcreteStrategy1 extends Strategy{
public void strategyInterface(){
//write you algorithm code here
//写自己独特的算法
}
}
从中可以看出,策略模式并不负责安排哪种情况应用哪种算法,
需要客户端来指定。策略模式只能同时应用一种策略。
在Java中BorderLayout,排序算法等地方都应用了Strategy模式。
可以应用在不同商品的打折算法不一样上
13,模板模式(Template Method):是类的行为模式,准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类来实现剩下的逻辑方法,不同的子类可以有不同的实现形式,从而对剩余的逻辑有不同的实现,这就是模板模式的用意。
代码实例:
abstract public class AbstractClass{
public void TemplateMethod() { //先实现一个模板方法,这是子类都要用的方法
doOperation1();
doOperation2();
doOperation3();
}
protected abstract void doOperation1();//定义抽象方法,需要不同的子类自己完成
protected abstract void doOperation2();
private final void doOperation3(){
//do something
}
}
public class ConcreteClass extends AbstractClass { //继承抽象类,实现抽象方法
public void doOperation1() {
//write your code here
System.out.println("doOperation1();");
}
public void doOperation2() {
//The following should not happen:
//doOperation3();
//write your code here
System.out.println("doOperation2();");
}
}
在java中这是常用的技巧,可以解决代码复用的问题
在java中的web系统中 HttpServlet就是建立在模板模式的基础之上的。HttpServlet提供了一个service()方法,这个方法调用7个do方法中的一个或几个,完成客户端的处理,那么service()就是一个模板,其他的do方法就是就是基本方法
其他模式还有:责任链模式,命令模式,状态模式,解释器模式,调停者模式,这就不多讲了
简单工厂模式的缺点是对“开-闭”原则的支持不够,因为如果有新的产品加入到系统中去,
就需要修改工厂类,将必要的逻辑加入到工厂类中
应用:在ejb和spring的大量使用,java2.0对代理的支持:自jdk1.3以来java通过java.lang.reflect提供三个直接的代理模式:Proxy , InvocationHandler ,Method