Java 的 23 种设计模式总结
1. 绪论
在学习这 23 种设计模式之前,一定要搞清楚一些基本的软件工程知识。包括绘制用例
图,类图 UML 图等知识。
先来看看什么是 UML。
UML(unified model language)统一建模语言。是一种标准的图形化建模语言。主要用于软
件的分析和设计,用定义完善的符号来图形化展示软件系统。UML 不涉及编程问题,即与
语言平台无关,就使得开发人员可以专注于建立软件系统的模型和结构。
结构图中比较常用的是类图和对象图。行为图比较常用的有用例图,状态机图,顺序图。
类图学习:
类图又三部分组成:类名,属性,方法
各个类之间的关系有以下这些:
Is-a 关系:继承关系
1
接口与实现之间的关系:跟继承的区别在于线条是虚线。
依赖关系:对象之间最弱的一种关联方式,是临时性的关联。一般指局部变量,函数参数,
返回值建立的对于其他对象的调用关系。一个类调用被依赖类中的某些方法而得以完成这个
类的一些指责。在类图使用带箭头的虚线表示,箭头从使用类指向被依赖的类。
关联:对象之间的一种引用的关系,比如客户类与订单类之间的关系。这种关系通常使用类
的属性表达。关联又分为一般关联,聚合关联与组合关联。后两种后面分析,在类图中使用
带箭头的实现表示关联,箭头从使用类指向被关联的类,可以是双向的。
聚合:表示 has-a 关系,是一种不稳定的包含关系,较强于一般的关联,有整体和局部的关
系 , 并 且 没 有 整 体 , 局 部 也 可 以 单 独 存 在 。
2
组合:表示 contains-a 关系,是种强烈的包含关系。组合类肤质被组合类的生命周期。是一
种强的聚合关系。部分不能脱离整体存在。如公司和部门。没有公司,部门也不存在了。类
图中用实心菱形表示,菱形从局部指向整体。
要注意区分聚合和组合,好聚好散,因此聚合的关系没有组合那么强烈。而组合关系的 part
是不可单独存在的。例如 company 和 apartment。
多重关系
通常在关联,聚合,组合中使用。就是代表有多少个关联对象存在。使用数字..星号表
示,如上图,一个割接通知可以关联 0 到 N 个故障单。
通过上面的分析,我想类图的概念大概是有了,主要包括关联(实心箭头),聚合(空
心菱形),组合(实心菱形),依赖(虚箭头),继承(实线+三角形),实现(虚线+三角形)。
我们在将下面这些设计模式的时候会用到类图和这些关系。
一、创建型模式
2. 简单工厂模式
一个工厂生产很多的产品。包含了一个接口,若干个实现类,以及一个工厂来生产这些
实现类。我们以生产 Fruit 来加以说明。
3
类图如下:
System.out.println("生产了一个苹果");
System.out.println("生产了一个橘子");
public void display();
public void display(){
}
代码非常简单:
接口 Fruit
public interface Fruit {
}
实现类:Apple
public class Apple implements Fruit {
}
实现类:Orange
public class Orange implements Fruit{
public void display(){
}
}
工厂类:Factory
public class Factory {
}
public Fruit getFruit(int type){
}
fruit=new Apple();
break;
Fruit fruit=null;
switch(type){
case 0:
case 1:
}
return fruit;
fruit=new Orange();
break;
4
+display()Apple+display()Orange+display()<>Fruit+getFruit() : FruitFactory
public static void main(String[] args){
}
Factory f=new Factory();
f.getFruit(0).display();
f.getFruit(1).display();
测试类:
public class Test {
}
测试结果:
生产了一个苹果
生产了一个橘子
总结:
简单工厂模式非常的简单,生产实例的过程在工厂中进行,并且选择的过程也是在工厂
里进行的。这样如果增加了新的实现,不如榴莲类,那么需要改工厂类,这违背了可扩展原
则。因此下面的工厂方法模式很好的解决了这个问题。使得改动只发生在客户端,不会对原
来的类进行修改。
3. 工厂方法模式
看类图
较之上面的类图,多了一个 factory,这样一旦有新的实现加入,只需要再加入新的工
厂,这样不用改变原有的代码了。
具体代码实现:
Fruit 接口:不变
public interface Fruit {
}
实现类 Apple 和 Orange 不变
public class Apple implements Fruit {
}
Orange
public class Orange implements Fruit{
public void display(){
}
public void display();
System.out.println("生产了一个苹果");
5
+display()Apple+display()Orange+display()<>Fruit+getOrange() : FruitAppleFactory+getApple() : FruitOrangeFactory
System.out.println("生产了一个橘子");
Fruit fruit=new Apple();
return fruit;
public void display(){
}
}
AppleFactory
public class AppleFactory {
public Fruit getApple(){
}
}
OrangeFactory
public class OrangeFactory {
public Fruit getOrange(){
}
}
Test(客户端程序)
public class Test {
}
测试结果:
生产了一个苹果
生产了一个橘子
Fruit fruit=new Orange();
return fruit;
public static void main(String[] args){
}
Fruit f=new AppleFactory().getApple();
f.display();
f=new OrangeFactory().getOrange();
f.display();
结果和简单工厂模式一样,但是工厂方法模式具有更好的可扩展形,且把判断逻辑移到
了客户端。当时同样带来问题,如果实现很多,那么每个实现对应一个工厂类多么的麻烦啊。
有没有解决方法,有的,那就是反射机制。Class.forName(“package.class”).newInstance();
4. 抽象工厂模式
与之前不同,这里不再是一个接口,而是两个接口。即划分事物的方法存在了两个维度。
用猫,狗作为例子,对于猫有白猫和黑猫。对于狗有白狗和黑狗。
维度 1:动物类型划分,猫和狗
维度 2:按颜色分,白和黑。
对于接口是按照动物类型划分的。而工厂则是按照颜色类型划分的。即一个工厂可以生
产一个颜色的两种动物类型。下面看看类图你就清楚了。
6
public void display();
public void display();
public void display() {
}
代码实现:
Dog 接口:
public interface Dog {
}
Cat 接口:
public interface Cat {
}
BlackDog 实现:
public class BlackDog implements Dog {
}
WhiteDog 实现
public class WhiteDog implements Dog {
}
BlackCat 实现
public class BlackCat implements Cat {
}
WhiteCat 实现
public class WhiteCat implements Cat {
public void display() {
}
public void display() {
System.out.println("生产了一只白猫");
7
System.out.println("生产了一只黑狗");
public void display() {
}
System.out.println("生产了一只白狗");
System.out.println("生产了一只黑猫");
+display()WhiteCat+display()<>Dog+display()<>Cat+display()BlackCat+display()WhiteDog+display()BlackDog+getBlackCat() : Cat+getBlackDog() : DogBlackFactory+getWhiteCat() : Cat+getWhiteDog() : DogWhiteFactory
}
public Dog getBlackDog(){
return new BlackDog();
}
public Cat getBlackCat(){
return new BlackCat();
}
}
BlackFactory
public class BlackFactory {
}
WhiteFactory
public class WhiteFactory {
}
Test
public class Test {
}
测试结果:
生产了一只黑猫
生产了一只黑狗
生产了一只白猫
生产了一只白狗
public Dog getWhiteDog(){
return new WhiteDog();
}
public Cat getWhiteCat(){
return new WhiteCat();
}
public static void main(String[] args){
BlackFactory bf=new BlackFactory();
bf.getBlackCat().display();
bf.getBlackDog().display();
WhiteFactory wf=new WhiteFactory();
wf.getWhiteCat().display();
wf.getWhiteDog().display();
}
5. 单例模式
该类只能产生一个对象,所以不能使用new方法创建对象,只能使用该类提供的方法
getInstance()创建对象。所有构造函数声明为私有的类型,并不做任何事情,防止别人调用。
且类内部有一个类的对象,getInstance就是获取该对象。
下面是类图表示,整个关系只涉及到一个类。但是类中有包含一个自己的实例对象。
如图:
8