用例、类、时序、顺序这几个图是比较重要的
用例图确定需求,顺序图确定对象间的协作,类图确定系统的结构(敏捷建模)
JMS的两种机制:队列机制(Queue)和主题机制(Topic)
队列机制:我发一个,对方取一个
主题机制:我发一个主题,发给所有订阅了这个主题的人
Sender发消息给服务器,服务器发现这个消息后通知receiver,receiver知道后就来
服务器上取这个消息了。
JMS是异步的,不是同步的。
====================================================================
在面向对象设计的演化过程中,最重要的事情就是设计模式的诞生。
1995年出版的《Design Patterns,Elements of Reusable Object-Oriented Software》
被认为是设计模式发展的里程碑,已经成为软件设计与开发人员的必修课程。
这本书的作者一共有四个人,通常称他们是GOF(Gang Of Four)
国内有一个名叫颜宏的人写了一本叫做《java与模式》的书,非常的厚,但是好像废话比较多。
Erich Gamma(瑞士国际面向对象技术软件中心的技术主管)
还是JUnit开源框架的作者之一,同时还是著名的Eclipse的主要奠基人
设计模式提倡的两大核心思想(面向接口,而非面向具体的实现;对象组合,提倡优先使用对象组合,而非继承)
继承被成为白箱复用,组合被称为黑箱复用。
23种设计模式依据两种准则对他们进行分类:目的准则、范围准则
目的准则:创建型模式(比如单例模式)、结构型模式(比如adaptor适配器模式)、行为模式(观察者模式)
范围准则:类模式(继承方式)、对象模式(对象组合)
目的准则以模式功能为分类标准。
创建型模式将对象的部分创建工作延迟到子类,而创建型对象模式则将它延迟到另一个对象中。
结构型类模式使用继承机制
-------------------------------------------------------
创建型模式(取代直接new对象的方式,这种方式导致这个类紧耦合了,为了类的实现和系统松
耦合,所以出现创建型模式)
单例模式、原型模式、工厂方法、抽象工厂、生成器
单例模式(Singleton):保证一个类只有一个实例
原型模式(Prototype):用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
工厂方法(Factory Method):提供一个用于创建对象的接口,让子类决定实例化哪一个类
抽象工厂(Abstract Factory):提供一个创建一系列相关或者相互依赖对象的接口,而无需指定
他们具体的类。
生成器(Builder)
---------------------------------------------
单例模式就是通过把构造方法弄成私有来保证客户无法任意创建对象。对象的单例是相对于的是java的
类加载器来说的。
声明时初始化静态单例变量
类加载时初始化静态单例变量(静态块)
在得到实例的方法中初始化静态单例变量
//惰性单例模式
public class Singleton
{
private static Singleton instance ;
private Singleton()
{}
public static Singleton getInstance()
{
if(instance==null)
{
instance = new Singleton();
}
return instance ;
}
};
//如果是非惰性呢?
public class Singleton
{
//private static Singleton instance = new Singleton();
static
{
private static Singleton instance = new Singleton();
}
private Singleton()
{}
public static Singleton getInstance()
{
return instance ;
}
};
初始化,构造方法外面的声明或是块中的声明谁在前面谁先初始化,
注意构造函数的初始化是在最后进行的。
常量不一定要在声明的时候赋值,但是它必须在构造函数之前赋值,且只能赋值一次。
伪单例模式:
相对线程单例(Hibernate中的ThreadLocal)、相对类加载器单例(BeanUtils和BeanUtilsBeans
就用到了这种单例模式)、相对特定上下文单例
线程单例保证在一个线程中只有一个实例,在java中可以通过ThreadLocal实现
Prototype模式:
将一个对象原封不动的复制给另外一个对象而且又不需要直接创建对象。
不创建对象,而通过已经有的对象进行复制,这个已经有的对象通常称为原型。
深拷贝和浅拷贝:
java语言已经将原型模式固化到对象中了,因此可以通过Object.clone以及Cloneable
接口配合实现。
--------------------------------------
Factory Method模式:
类A要创建类B,但是不知道类B的类型是什么……
工厂模式:工厂模式是一种经常被使用到的模式,根据工厂模式实现的类可以根据提供的数据
生成一组类中某一个类的实例,通常这一组类有一个公共的抽象父类并且实现了相同的方法,
但是这些方法针对不同的数据进行了不同的操作。首先需要定义一个基类,该类的子类通过不
同的方法实现了基类中的方法。然后需要定义一个工厂类,工厂类可以根据条件生成不同的子
类实例。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一
个子类的实例。
植物都会开花结果,但是植物本身是一个抽象的概念,只有具体的植物(桃树、梨树等等)
才会结出具体的果实(Fruit),将植物产果的逻辑延迟到具体的植株上去。
//使用抽象方法或接口的形式将对象的实现延迟到具体子类中去。
public abstract class Plant
{
public abstract Fruit createFruit();
public void grow()
{
System.out.println("开花");
createFruit().info();
}
}
public abstract class Fruit
{
public abstract void info() ;
}
public class PeachPlant extends Plant
{
public Fruit createFruit()
{
return new PeachFruit();
}
}
public class PeachFruit extends Fruit
{
public void info()
{
System.out.println("桃树结果");
}
}
public class Demo
{
public static void main(String[] args)
{
Plant peach = new PeachPlant();
peach.grow();
}
}
Collectin的iterator方法返回Iterator可认为是工厂方法的一种
典型应用,Hibernate中的SessionFactory.openSession,
Spring中的BeanFactory.getBean,FactoryBean.getObject
都是
----------------------------------------
Abstract Factory模式:
一组对象间有相互依赖和协作的关系,称为一个产品系。如何保证它们能够正确的
搭配工作?
抽象的CPU、由它继承两个:一个是笔记本的CPU、一个台式机的CPU
同理,主板、内存、硬盘等也是类似的道理
抽象工厂下面有两个具体的工厂,一个工厂具体生产笔记本、一个工厂具体生产台式机。
要有一个工厂的体系,还要有一个产品的体系,用工厂来制造产品
先做一个抽象的工厂ComputerFactory
public abstract class ComputerFactory
{
public abstract Mainboard createMainboard();
public abstract HardDisk createHardDisk();
}
具体的工厂NotebookComputerFactory
public class NotebookComputerFactory extends ComputerFactory
{
public HardDisk createHardDisk()
{
return new NoteHardDisk();
}
public HardDisk createHardDisk()
{
return new NoteMainBoard();
}
}
定义抽象产品系:Mainboard、Harddisk(主板和硬盘)
public abstract class Mainboard
{
public abstract void addHardDisk(HardDisk hd) ;
}
//笔记本的主板
public class NoteMainboard extends Mainboard
{
public void addHardDisk(HardDisk hd)
{
System.out.println("在笔记本电脑的主板上加入了笔记本的硬盘!");
}
}
//笔记本的硬盘
public class NoteHardDisk extends HardDisk
{
}
//只要给了生产笔记本的工厂,那么该工厂生产的部件一定是笔记本的部件,
//就是这个意思。
ComputerFactory cf = new NotebookComputerFactory();
Mainboard mb = cf.createMainboard();
HardDisk hd = cf.createHardDisk();
mb.addHardDisk(hd);
在java中抽象工厂的典型应用就是JMS(队列机制和主题机制)
发送者和接收者本身就是两种抽象的产品系,每种产品系都有两套机制,一套
是队列机制,一套就是主题机制。
只有队列机制的发送者才能和队列机制的接收者通信。
在j2ee1.4的api中的javax.jms包里面可以看到JMS是使用了抽象工厂的模式:
MessageProducer接口下面有QueueSender和TopicPublisher两个子类
ConnectionFactory下面有两个具体的工厂:QueueConnectionFactory和
TopicConnectionFactory分别生产队列机制和主题机制的产品(接收者和发送者)
-----------------------------------
抽象工厂与工厂方法到底什么区别?
二者之间联系大于区别,抽象工厂一般是通过工厂方法来实现的。
二者区别并不明显,工厂方法只是抽象工厂模式的一种实现方法而已。抽象工厂模式
的实现也可以使用原型模式(抽象工厂强调工厂之间的协作)
工厂方法实现抽象工厂模式:必须为每个产品系都做出一个新的工厂,而且无法在已有的产品系中
增加新的产品。
使用原型模式实现抽象工厂不能保证生产出来的产品相互之间的协调。
public class ComputerFactory
{
public Mainboard createMainboard(Mainboard mb) throws Exception
{
return (Mainboard)mb.clone();
}
public HardDisk createHardDisk(HardDisk hd) throws Exception
{
return (HardDisk)hd.clone();
}
}
public abstract class HardDisk implements Cloneable
{
public Object clone()
{
return super.clone();
}
}
public abstract class Mainboard implements Cloneable
{
public Object clone()
{
return super.clone();
}
}
main函数:
ComputerFactory cf = new NotebookComputerFactory();
Mainboard mb = cf.createMainboard(new NoteMainboard());
HardDisk hd = cf.createHardDisk(new NoteHardDisk());
-------------------------------------------------------
创建型模式的最后一种模式:Builder模式。
如果构造对象的过程比较复杂,并且可能构造的对象也是不可预测的,希望
将构造过程独立出来,变得可插拔,应该如何实现?
一家综合餐馆,既可以做中餐,又可以做西餐,编写程序使得餐馆与所做的食品
松耦合,能够让餐馆随时加入其他风格的食品,比如日本料理。
Restaurant这个类里面有一系列的班子(厨房),这些厨房是可以替换的,
可以随时替换。
public class Restaurant
{
private Kitchen kit ;
private ArrayList res ;
public Restaurant()
{
res = new ArrayList() ;
res.add("rice");
res.add("meat");
res.add("dish");
}
public void setKit(Kitchen kit)
{
this.kit = kit ;
}
public Food makeFood()
{
return kit.getFood(res) ;
}
}
public abstract class Kitchen
{
public abstract Rice buildRice();
public abstract Dish buildDish();
public abstract Meat buildMeat();
public abstract Food getFood(ArrayList res) ;
}
public ChineseFoodKitchen extends Kitchen
{
public Rice buildRice()
{
return new Rice() ;
}
public Dish buildDish()
{
return new Dish() ;
}
public Meat buildMeat()
{
return null ;
}
public Food getFood(ArrayList res)
{
ChineseFood food = new ChineseFood();
return null ;
}
}
public class Dish
{
}
public class Rice
{
}
public class Meat
{
}
public class Food
{
private Rice rice ;
private Dish dish ;
//getter和setter方法略
}
--------------------------------------------
写简单点来说就是:
Restaurant r = new Restaurant();
Kitchen k1 = new ChineseFoodKitchen() ;
r.setKit(k1);
System.out.println(r.makeFood().toString());
Kitchen k2 = new WesternFoodKitchen() ;
r.setKit(k2);
System.out.println(r.makeFood().toString());
通过不同的厨房来构筑饭店,只需要饭店中的setter方法改变厨房即可
改变makeFood的具体行为(makeFood方法通过调用具体厨房的getFood
方法决定饭菜的种类)。
在ConvertUtils中对Builder模式应用的很典型。
======================================================
上面是五种创建型模式(单例模式、原型模式、工厂方法、抽象工厂、创建模式)……
接下来是结构型模式
结构型模式:如何组合类和对象以获得更大的结构,采用继承机制来组合接口或实现。
Adapter、Bridge、Composite、Decorator、Facade、Flyweight、Proxy
适配器、桥接、组成、装饰、外观、享元、代理
-----------------------------------------------------
Adapter:如何将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口
不兼容而不能在一起工作的那些类可以一起工作。
比如:老系统使用JDK较早版本,因此只能够读取Enumeration类型的集合;而
新系统由于使用了新版本JDK,所以提供的集合都是List类型的。现在在不更改新、
老系统的情况下,如何让老系统能够顺利读取新系统提供的集合?
也就是提供的数据是List类型,但是旧的系统只能够接收Enumeration类型
如何把List类型包成Enumeration类型传给新系统?
可以考虑建立一个Adapter继承Enumeration,当然这个Adapter肯定得重写
Enumeration里面的nextElement方法和hasMoreElement方法,同时Adapter
里面再组合一个List就可以了。(通过构造器)也就是对象组合方式
之所以要组合一个List,是要把新版本的这个List里面的对应方法拿出的数据
转到Enumeration中的对应方法中去,从而将这个继承了Enumeration的Adapter
能够顺利的传到老系统中去 。
还有一种多继承的方式。(java中只能使用接口的方式来做了,在上面的例子
里面就是同时继承List和Enumeration)
在实际中的应用场合:
AWT中的监听器
IO中的InputStreamReader和OutputStreamWriter
----------------------------------------------------------
Bridge模式:
抽象与具体是不是一定要通过继承来实现?使用继承会有紧耦合的问题
抽象与具体通过继承实现的时候,将抽象与具体紧密耦合,抽象层面的每一次扩充都会
导致具体层面的扩充。
手机可以传递两种信息、语言信号Phone和文本信号Text,同时,手机通信有GSM和
CDMA两种通信网络。现在要建立信号(Signal)的类体系,能够描述GSM的语言信号、
GSM文本信号、CDMA语言信号,CDMA文本信号,如果现在还需要传递视频信号Video
,那么又该如何实现?
将抽象层和具体实现层隔离开,
分成信号类型和网络类型两个体系:
public abstract class Signal
{
protected Network net ;
public void setNetwork(Network net)
{
this.net = net ;
}
public abstract String getCode() ;
}
public abstract class Network
{
public abstract void decode();
public abstract String getNetType() ;
}
public class TextSignal extends Signal
{
public String getCode()
{
return "使用"+net.getNetType()+"的文本信号" ;
}
}
public class PhoneSignal extends Signal
{
public String getCode()
{
return "使用" + net.getNetType() + "的语音信号!" ;
}
}
public class GSMNet extends Network
{
public void decode(){}
public String getNetType()
{
return "GSM网络" ;
}
}
public class CDMANet extends Network
{
public void decode(){}
public String getNetType()
{
return "CDMA网络" ;
}
}
public static void main(String[] args)
{
Signal s = new TextSignal() ;
Network netFirst = new GSMNet() ;
Network netSecond = new CDMANet() ;
s.setNetwork(netFirst);
System.out.println(s.getCode());
}
桥模式应用的场景:一种事物具有两种特征,而且这两种特征可以各自作为独立体系出现。
最主要是在两个需要协作,又可以独立成为体系的对象之间使用桥模式。选择主系类,并
使主系类中包含次系类的顶层实现。
桥模式的典型应用:JDBC中的Connection和Driver之间的关系、
Hibernate中的Query和Dialect之间的关系。