一.Creational patterns 创造型模式
Factory 工厂模式*
概念
当client不知道要创建哪个具体类的实例,或者不想在client代码中指明要具体创建的实例时,用工厂方法。
定义一个用于创建对象的接口,让其子类来决定实例化哪一个类,从而使一个类的实例化延迟到其子类。
使用场景
- jdbc连接数据库
- 硬件访问
- 降低对象的产生和销毁
区别:
通常情况下进行对象创建:(client直接创建具体对象)
Product p = new ProductTwo();
工厂模式下:
Product p = new ConcreteTwo().makeObject();
代码示例
//工厂实现的接口
interface TraceFactory {
public Trace getTrace();
public Trace getTrace(String type);
void otherOperation(){};//还可实现其他功能
}
//工厂方法的实现
public class Factory1 implements TraceFactory {
//有新的具体类时 可以在工厂类里修改或增加新的工厂函数 不影响客户端代码
public Trace getTrace() {
return new SystemTrace();
}
}
public class Factory2 implements TraceFactory {
public Trace getTrace(String type) {//根据输入类型决定创建哪个具体产品
if(type.equals(“file”)
return new FileTrace();
else if (type.equals(“system”)
return new SystemTrace();
}
}
也可采用静态工厂方法实现,在获取想要得到的产品时不需将工厂类实例化,直接调用工厂方法即可
遵循OCP原则:对扩展的开放,对修改已有代码的封闭
Abstract Factory 抽象工厂模式
概念
提供接口以 创建一组相关/相互依赖的对象 ,但不需要指明其具体类。
解决类似固定搭配的问题
注释:
创建的不是一个完整产品,而是“产品族”(遵循固定搭配规则的多类产品的实例),得到的结果是:多个不同产品的object,各产品创建过程对client可见,但“搭配”不能改变。
本质上,Abstract Factory是把多类产品的factory method组合在一起
如果不使用抽象工厂,直接采用各类的工厂可能会导致搭配错误
抽象工厂模式与工厂模式的区别
抽象工厂模式 | 工厂模式 |
---|---|
创建多个类型的对象 | 创建一个对象 |
多个factory方法 | 一个factory方法 |
使用组合/委派 | 使用继承/子类型 |
Builder 构造器模式
概念
创建复杂对象,包含多个组成部分。将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
与抽象工厂模式的区别:
client要的不是一堆零散的objects (abstract factory那样的结果),而是一个完整的产品,client不关心其中的细节组成部分是什么、如何创建
- 抽象工厂模式:创建的不是一个完整产品,而是“产品族”(遵循固定搭配规则的多类产品实例),得到的结果是:多个不同产品的实例object,各产品创建过程对client可见,但“搭配”不能改变。
- 构造器模式:创建的是一个完整的产品,有多个部分组成,client不需了解每个部分是怎么创建、各个部分怎么组合,最终得到一个产品的完整object
Product 产品类: 通常是实现了模板方法模式,也就是有模板方法和基本方法。
Builder 抽象建造者: 规范产品的组建,一般是由子类实现。
ConcreteBuilder 具体建造者: 实现抽象类定义的所有方法,并且返回一个组建好的对象。
Director 导演类: 负责安排已有模块的顺序,然后告诉 Builder 开始建造
使用场景
-
相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式。
-
多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。
-
产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适。
代码示例
/* "Product" */
class Pizza {
private String dough = "";
private String sauce = "";
private String topping = "";
public void setDough(String dough) {
this.dough = dough;
}
public void setSauce(String sauce) {
this.sauce = sauce;
}
public void setTopping(String topping) {
this.topping = topping;
}
}
/* "Abstract Builder" */
abstract class PizzaBuilder {
protected Pizza pizza;
public Pizza getPizza() {
return pizza;
}
public void createNewPizzaProduct() {
pizza = new Pizza();
}
public abstract void buildDough();
public abstract void buildSauce();
public abstract void buildTopping();
}
/* "ConcreteBuilder 1" */
//具体的builder子类中,override三个抽象方法,分别构建三个parts
class SpicyPizzaBuilder extends PizzaBuilder {
public void buildDough() {
pizza.setDough("pan baked");
}
public void buildSauce() {
pizza.setSauce("hot");
}
public void buildTopping() {
pizza.setTopping("pepperoni+salami");
}
}
/* "ConcreteBuilder 2" */
class HawaiianPizzaBuilder extends PizzaBuilder {
public void buildDough() {
pizza.setDough("cross");
}
public void buildSauce() {
pizza.setSauce("mild");
}
public void buildTopping() {
pizza.setTopping("ham+pineapple");
}
}
/* "Director" */
class Waiter {
private PizzaBuilder pizzaBuilder;
public void setPizzaBuilder(PizzaBuilder pb) {
pizzaBuilder = pb;
}
public Pizza getPizza() {
return pizzaBuilder.getPizza();
}
public void constructPizza() {
pizzaBuilder.createNewPizzaProduct();
pizzaBuilder.buildDough();
pizzaBuilder.buildSauce();
pizzaBuilder.buildTopping();
}
}
/* A customer ordering a pizza. */
public class PizzaBuilderDemo {
public static void main(String[] args) {
Waiter waiter = new Waiter();
PizzaBuilder hawaiianPizzabuilder = new HawaiianPizzaBuilder();//Client使用不同的builder子类创建不同的产品
PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();
waiter.setPizzaBuilder( hawaiianPizzabuilder );//建立waiter和builder之间的delegation关系
waiter.constructPizza();
Pizza pizza = waiter.getPizza();
}
}
二. Structural patterns 结构型模式
Bridge 桥连模式
概念
通过delegation+inheritance建立两个具体类之间的关系;将抽象和实现解耦, 使得两者可以独立地变化。
Abstraction——抽象化角色: 它的主要职责是定义出该角色的行为,同时保存一个对实现化角色的引用,该角色一般是抽象类。
Implementor——实现化角色: 它是接口或者抽象类,定义角色必需的行为和属性。
RefinedAbstraction——修正抽象化角色: 它引用实现化角色对抽象化角色进行修正。
ConcreteImplementor——具体实现化角色: 它实现接口或抽象类定义的方法和属性。
与策略模式的区别
-
Bridge: structural pattern 强调双方的run time delegation linking
一个类A的对象中有其他类B的对象作为其组成部分,但A的对象具体绑定到B的哪个具体子类的实现?在运行时通过delegation加以组合,并永久保存这种delegation关系。 -
Strategy: behavioral pattern 强调一方run-time使用另一方的“算法”
“算法”通常实现为“类的某个方法”的形式,strategy的目的并非在“调用算法的类”与“被调用算法所在的类”之间建立起永久联系,而只是帮助前者临时使用后者中的“算法”,前者无需永久保存后者的实例。
使用场景
- 不希望或不适用使用继承的场景
- 接口或抽象类不稳定的场景
- 重用性要求较高的场景
代码示例
public class Circle extends Shape {
private int x, y, radius;
public Circle(int x, int y, int radius, DrawAPI drawAPI) {
super(drawAPI);
this.x = x;
this.y = y;
this.radius = radius;
}
public void draw() {
drawAPI.drawCircle(radius,x,y);//将draw这个责任delegate到drawAPI这个接口的具体实例去执行
}
}
Proxy 代理模式
概念
为其他对象提供一种代理以控制对这个对象的访问
与Adaptor模式的区别:
Adapter: structural pattern,目的:消除不兼容,目的是B以客户端期望的统一的方式与A建立起联系
Proxy: behavioral pattern 目的:隔离对复杂对象的访问,降低难度/代价,定位在“访问/使用行为”
分类
-
普通代理: 在该模式下,调用者只知代理而不用知道真实的角色是谁,屏蔽了真实角色的变更对高层模块的影响,真实的主题角色想怎么修改就怎么修改,对高层次的模块没有任何的影响,只要你实现了接口所对应的方法,该模式非常适合对扩展性要求较高的场合。
-
强制代理: 强制代理的概念就是要从真实角色查找到代理角色,不允许直接访问真实角色。高层模块只要调用 getProxy 就可以访问真实角色的所有方法,它根本就不需要产生一个代理出来,代理的管理已经由真实角色自己完成。
区别:普通代理就是我们要知道代理的存在,也就是类似的 GamePlayerProxy 这个类的存在,然后才能访问;强制代理则是调用者直接调用真实角色,而不用关心代理是否存在,其代理的产生是由真实角色决定的。
- 动态代理: 根据被代理的接口生成所有的方法,也就是说给定一个接口,动态代理会宣称“我
已经实现该接口下的所有方法了”。两条独立发展的线路。动态代理实现代理的职责,业务逻辑 Subject 实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。通知 Advice 从另一个切面切入,最终在高层模块也就是 Client 进行耦合,完成逻辑的封装任务。
意图:横切面编程,在不改变我们已有代码结构的情况下增强或控制对象的行为。
首要条件:被代理的类必须要实现一个接口。
代码示例
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName){
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {…}
private void loadFromDisk(String fileName){…}//不使用代理模式 每次加载的代价很高
}
public class ProxyImage implements Image {
private Image realImage;
private String fileName;
public ProxyImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null){ //当display时发现对象没有被加载在进行delegation
realImage = new RealImage(fileName);
}
realImage.display();
}
}
Composite 组合模式
概念
将对象组合成树形结构以表示 “部分-整体” 的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
与Decorator区别:
Composite: structural pattern 目的是在同类型的对象之间建立起树型层次结构,一个上层对象可包含多个下层对象
Decorator: structural pattern 强调的是同类型对象之间的“特性增加”问题,它们之间是平等的,区别在于 “拥有特性”的多少,每次decoration只能作用于一个object。
使用场景
-
维护和展示部分-整体关系的场景,如树形菜单、文件和文件夹管理。
-
从一个整体中能够独立出部分模块或功能的场景。
-
只要是树形结构,就考虑使用组合模式。
代码示例
public class Composite extends Component {
//构件容器
private ArrayList<Component> componentArrayList = new
ArrayList<Component>();
//增加一个叶子构件或树枝构件
public void add(Component component){
this.componentArrayList.add(component);
}
//删除一个叶子构件或树枝构件
public void remove(Component component){
this.componentArrayList.remove(component);
}
//获得分支下的所有叶子构件和树枝构件
public ArrayList<Component> getChildren(){
return this.componentArrayList;
}
}
三.Behavioral patterns
Observer 观察者模式***
概念
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
Subject 被观察者: 定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。
Observer 观察者: 观察者接收到消息后,即进行 update(更新方法)操作,对接收到的信息进行处理。
ConcreteSubject 具体的被观察者: 定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。
ConcreteObserver 具体的观察者: 每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。
使用场景
- 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
- 事件多级触发场景。
- 跨系统的消息交换场景,如消息队列的处理机制。
代码示例
public class Subject {
private List<Observer> observers = new ArrayList<Observer>();//维持一组“对自己感兴趣的”对象
private int state;
public int getState() {return state;}
public void setState(int state) {
this.state = state;
notifyAllObservers();//在自己状态变化时,通知所有“粉丝”
}
//允许“粉丝”调用该方法向自己注册,将其加入队列
public void attach(Observer observer){observers.add(observer);}
private void notifyAllObservers(){
for (Observer observer : observers) {
observer.update();
}
}
}
//粉丝的抽象接口
public abstract class Observer {
protected Subject subject;
public abstract void update();
}
public class BinaryObserver extends Observer{
//构造时,指定自己的“偶像”subject,把自己注册给它
public BinaryObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Binary String: " + Integer.toBinaryString( subject.getState() ) );
}
}
Vistor 访问者模式
概念
本质上:将数据和作用于数据上的某种/些特定操作分离开来(封装一些作用于某种数据结构中的各元素的操作, 它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。)
为ADT预留一个将来可扩展功能的“接入点”,外部实现的功能代码可以在不改变ADT本身的情况下通过delegation接入ADT
Visitor——抽象访问者: 抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是 visit 方法的参数定义哪些对象是可以被访问的。
ConcreteVisitor——具体访问者: 它影响访问者访问到一个类后该怎么干,要做什么事情。
Element——抽象元素: 接口或者抽象类,声明接受哪一类访问者访问,程序上是通过 accept 方法中的参数来定义的。
ConcreteElement——具体元素: 实现 accept 方法,通常是 visitor.visit(this),基本上都形成了一种模式了。
ObjectStruture——结构对象: 元素产生者,一般容纳在多个不同类、不同接口的容器,如 List、Set、Map 等,在项目中,一般很少抽象出这个角色。
和迭代器的区别:
- Iterator: behavioral pattern 迭代器:以遍历的方式访问集合数据而无需暴露其内部表示,将“遍历”这项功能delegate到外部的iterator对象。
- Visitor: behavioral pattern 在特定ADT上执行某种特定操作,但该操作不在ADT内部实现,而是delegate到独立的visitor对象,客户端可灵活扩展/改变visitor的操作算法,而不影响ADT
和策略模式的联系与区别
二者都是通过delegation建立两个对象的动态联系
- Visitor强调是的外部定义某种对ADT的操作,该操作于ADT自身关系不大(只是访问ADT),故ADT内部只需要开放accept(visitor)即可,client通过它设定visitor操作并在外部调用。
- Strategy则强调是对ADT内部某些要实现的功能的相应算法的灵活替换。这些算法是ADT功能的重要组成部分,只不过是delegate到外部strategy类而已。
区别:
- visitor是站在外部client的角度,灵活增加对ADT的各种不同操作(哪怕ADT没实现该操作)
- strategy则是站在内部ADT的角度,灵活变化对其内部功能的不同配置。
使用场景
-
一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作,也就说是用迭代器模式已经不能胜任的情景。
-
需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。
代码示例
public class CompensationVisitor implements Visitor {
// 将其中的数据和一些操作分离开
@Override
public void Visit(Element element) {
// TODO Auto-generated method stub
Employee employee = ((Employee) element);
System.out.println(
employee.getName() + "'s Compensation is " + (employee.getDegree() * employee.getVacationDays() * 10));
}
}
Mediator 中介者模式
概念
用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散, 而且可以独立地改变它们之间的交互。
使用场景
中介者模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是:在类图中出现了蜘蛛网状结构,即每个类都与其他的类有直接的联系。
Command 命令模式
概念
将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
使用场景
认为是命令的地方就可以采用命令模式,例如,在 GUI 开发中,一个按钮的点击是一个命令,可以采用命令模式;模拟 DOS 命令的时候,当然也要采用命令模式;触发-反馈机制的处理等。
Chain of responsibility 责任链模式
概念
使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
职责
抽象的处理者实现三个职责:
1、定义一个请求的处理方法 handleMessage,唯一对外开放的方法;
2、定义一个链的编排方法 setNext,设置下一个处理者;
3、定义了具体的请求者必须实现的两个方法:定义自己能够处理的级别getHandlerLevel 和具体的处理任务 echo。