设计模式之禅-2 设计模式
23 种设计模式
1 单例模式
定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
实现:private 修饰构造方法,在本类中提供静态方法获取唯一的实例。
使用场景:在一个系统中,要求一个类有且只有一个对象,如果出现多个对象会有“不良反应”,则可以采用单例模式。
实际使用:工具类,spring默认生成的bean。
可能引入的问题:多线程环境下单例可能存在线程安全问题。
2 工厂方法模式
定义:定义一个用于创建对象的接口,让子类去决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
使用方式:
//抽象产品类 public abstract class Product { public abstract void method(); } //产品实现类A public abstract class ProductA extend Product { public void method(){ } } //产品实现类B public abstract class ProductB extend Product { public void method(){ } } //抽象工厂类 public abstract class Factory { public abstract <T extends Product> T create(Class<T>c); } //抽象工厂类 public class ProductFactory extends Factory { public <T extends Product> T create(Class<T>c){ Product p = (Product)Class.forName(c.getName()).newInstance(); return (T)p; } }
使用场景:工厂方法模式是new一个对象的替代品,所以在所有需要生成对象的地方都可以使用,但是要考虑成本,以及是否增加复杂度。当需要一个灵活、可扩展的框架时可以考虑使用。
扩展:
- 简单工厂模式:一个模块只需要一个工厂类,没必要生产出来,直接使用静态方法。
- 升级为多个工厂类:为每个产品定义一个工厂类,由使用者选择使用哪个工厂。
- 替代单例模式。
- 延迟初始化:一个对象被消费完毕后,并不直接释放,工厂类保持其初始化状态。缓存已创建对象,重复使用。
3 抽象工厂模式
定义:为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类。
//抽象产品类phone public abstract class Phone { public abstract void phone(); } //产品实现类HWPhone public class HWPhone extend Phone { public void phone(){ } } //产品实现类MiPhone public class MiPhone extend Phone { public void phone(){ } } //抽象产品类PC public abstract class PC { public abstract void pc(); } //产品实现类HWPc public class HWPc extend PC { public void pc(){ } } //产品实现类MiPc public class MiPc extend PC { public void pc(){ } } //抽象工厂类 public abstract class AbstractCreator{ public abstract Phone phone(); public abstract PC pc(); } //产品等级1的实现类 public class HWCreator extends AbstractCreator { public abstract Phone phone(){ return new HWPhone(); } public abstract PC pc(){ return new HWPc(); } } //产品等级2的实现类 public class MiCreator extends AbstractCreator { public abstract Phone phone(){ return new MiPhone(); } public abstract PC pc(){ return new MiPc(); } } public static void main (String []args){ AbstractCreator crator = new HWCreator(); Phone phone = crator.phone(); Pc pc = crator.pc(); }
ps: 有N个产品族,在抽象工厂类中就因该有N个创建方法;有M个产品等级,就有M个实现工厂类,在每个实现工厂中,实现不同产品族的生产任务。
使用场景:一个对象族(或者一组没有任何关系的对象)有相同的约束,则可以使用抽象工厂模式。
缺点:产品族扩展非常困难。
4 模板方法模式
定义:定义一个操作中的算法的框架,而将一些步骤延迟到子类中。 使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。
模板模式仅使用了java的继承机制。其中AbstractClass叫做抽象模板,它的方法分为两类:
- 基本方法:是由子类实现的方法,并且在模板方法被调用。
- 模板方法:可以有几个,一般是一个具体的方法,也就是一个框架,实现对基本方法的调用,完成固定的逻辑。
ps:为防止恶意操作,一般模板方法中都加上final关键字,不允许被覆写。
public abstract class AbstractClass{ // 基本方法 public abstract void do someThing(); // 基本方法 public abstract void do anyThing(); // 模板方法 public void do templateMethod(){ this.someThing(); this.anyThing(); } }
使用场景:多个子类有公有的方法,并且逻辑相同
扩展:使用钩子方法,让子类的返回值决定公共部分的执行结构。
public abstract class AbstractClass{ // 基本方法 public abstract void doSomeThing(); // 基本方法 public abstract void doAnyThing(); // 模板方法 public void do templateMethod(){ this.doSomeThing(); if(select()){ this.doAnyThing(); } } // 钩子方法 protect abstract boolean select(); }
5 建造者模式
也称生成器模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
在建造者模式中,有四种角色:
- Product产品类,通常是实现了模板方法模式,也就是有模板方法跟基本方法。
- Builder抽象建造者,规范产品的组建,一般由子类实现。
- ConcreteBuilder 具体建造者,实现抽象类定义的所有方法,并且返回一个组建好的对象。
- Director 导演类,负责安排已有模块的顺序,然后告诉builder开始建造。
//产品类 public class Product{ } //抽象建造者 public abstract class Builder{ // 建造产品 public abstract Product builderProduct(); // 设置产品的不同部分,以获得不同的产品 public void setPart(); } //建造者实现类 public class concreteProduct extends Builer{ private Product product = new Product(); public void setPart(){ // 产品内部逻辑,修改product属性值 } public Product builderProduct(){ return product; } } //导演类 public class Director{ private Builder builder = new concreteProduct(); public Product getProductA(){ builder.setPart(); return builder.builderProduct(); } }
setPart()方法是零件的配置。什么是零件?其他的对象,获得一个不同零件,或者不同的装配顺序就可能产生不同的产品。
导演类的作用是封装,避免高层模块深入到建造者内部的实现类。
使用场景:
- 相同的方法,不同的执行顺序,产生不同事件结果。
- 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同。
- 建造者模式 vs 工厂模式: 建造者模式关注的是零件类型与装配顺序,工厂模式关注的是创建,创建零件是它的主要职责,组装顺序不是它关心的
6 代理模式(委托模式)
定义:为其他对象提供一种代理以控制对这个对象的访问。
public interface Subject{ public void request(); } public class RealSubject implements Subject{ public void request{ } } public class Proxy implements Subject{ private Subject subject; public Proxy(Subject subject){ this.subject = subject; } public void request(){ this.subject.request(); } }
使用场景:SpringAOP
扩展:
普通代理:普通代理就是我们要知道代理的存在,才能访问;强制代理则是调用者直接调用真实角色,而不用关心代理是否存在,其代理的产生是由真实角色决定的。
7 原型模式
定义:用原型实例制定创建对象的种类,并且通过拷贝这些原型创建新的对象。
应用:
优点:性能优良,原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好的多;可以逃避构造函数的约束,不会执行构造函数。
使用场景 :资源初始化场景,性能和安全要求场景(通过new 产生一个对象需要非常繁琐的数据准备或访问权限场景下可以使用此模式)
ps:注意深、浅拷贝(对象内部数组、引用对象都不拷贝,指向原生对象的内部元素地址);要使用clone方法,类的成员变量上不要增加final关键字。
实践:原型模式先产生一个包含大量共有信息的类,然后可以拷贝出副本,修正细节细腻些,建立了一个完整的个性对象。
8 中介者模式
定义:用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立的改变它们之间的交互。
中介者模式由以下几部分组成:
Mediator 抽象中介者角色:定义统一接口,用于各同事角色之间的通信。
Concrete Meditor 具体中介者角色:通过协调各同事角色实现协作行为,必须依赖各个同事角色。
Colleague 同事角色:每一个同事角色都知道中介者角色,而且与其他同事角色通信的时候,一定要通过中介者角色协作。每个同事类的行为分为两种,一种是同事本身的行为,比如改变自身状态,这种行为称为自发行为,与其他同事类或中介者没有任何依赖;第二种是必须依赖中介者才能完成的行为,叫做依赖方法。
// 抽象中介者 public abstract class Mediator{ //定义同事类 protect ConcreteColleague1 c1; protect ConcreteColleague2 c2; // getC1、setC1、 getC2、setC2 // 中介者模式的业务逻辑 public abstract void doSomething1(); public abstract void doSomething2(); } // 通用中介者 public class ConcreteMediator extends Mediator{ public void doSomething1(){ } public void doSomething2(){ } } //抽象同事类 public abstract Colleague{ protect Mediator mediator; public Colleague(Mediator mediator){ this.mediator = mediator; } } //具体同事类 public ConcreteColleague1 extends Colleague{ public Colleague(Mediator mediator){ this.mediator = mediator; } // 自有方法 public void doSomething1(){ } // 依赖方法 public void depDoSomthing1(){ super.mediator.doSomething1(); } }
优点:减少类间的依赖,把原有的一对多依赖变成了一对一的依赖,同事类只依赖中介者。
使用场景:类图中出现了“蜘蛛网”状的复杂依赖关系,通过中介者模式,改为星状结构。
9 命令模式
定义:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
三个角色:
reciver接收者:干活的角色,命令传递到这里是应该被执行的。
command命令角色:需要执行的命令都在这里声明。
Invoker角色:接收到命令,并执行命令。
public abstrat class Receiver{ public abstrace void doSomethig(); } public class ConcreteReciver extends Receiver { public void doSomethig(){ } } public abstrat class Command{ public abstrace void execute(); } public class ConcreteCommand extends Command{ private Receiver receiver; public ConcreteCommand (Receiver receiver){ this.receiver=receiver; } public void execute(){ this.receiver.doSomething(); } } public class Invoker{ private Command command; public Invoker(Command command){ this.command = command; } public void action(){ this.command.execute(); } } }
优点:类间解耦,调用者角色跟接收者角色之间没有任何依赖关系;Command子类可以非常容易的扩展。
使用场景:只要你认为是命令的地方都可以采用命令模式。
10 责任链模式
定义:使多个对象都有机会处理请求,从而避免了请求的发送者跟接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直至有对象处理它。
public abstract class Handler { private Handler nextHandler; public final Response handleMessage(Request request){ Respon respon = null; if(this.getHandlerLevel().equals(request.getRequestLevel())){ respon = this.proc(request); }else{ if(this.nextHandler!=null){ return this.nextHandler.handleMessage(request); } } return respon; } public void setNextHandler(Handler handler){ this.nextHandler=handler; } protect abstract Level getHandlerLevel(); protect abstract Respon proc(Request request); }
优点:将请求跟处理分开,请求者不需要知道谁处理的,处理者可以不用知道请求的全貌
11 装饰模式
定义:动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。
需要四个角色:
Component 抽象构件,是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象。
ConcreteComponent 具体构件:抽象构件的实现类,需要装饰的就是它。
Decorator 装饰对象: 一般是一个抽象类,它里面有一个private变量指向Component抽象构件。
具体装饰角色。
public abstract class Component{ public abstract void proc(); } public class ConcreteComponent extends Component{ public void proc(){ // do somthing } } public abstract class Decorator extends Component{ private Component component; public Decorator ( Component component){ this.component=component; } public void proc(){ this.component.proc(); } } public class ConcreteDecorator1 extends Decorator { public ConcreteDecorator1 ( Component component){ super(component); } private void method1(){ } public void proc(){ method1(); super.proc(); } } public class ConcreteDecorator2 extends Decorator { public ConcreteDecorator2 (Component component){ super(component); } private void method2(){ } public void proc(){ super.proc(); method2(); } } public class Client{ public static void main(String[] args){ Component component = new ConcreteComponent(); component = new ConcreteDecorator1(component); component = new ConcreteDecorator2(component); component .proc(); } }
优点:装饰类与被装饰类可以独立发展;装饰模式是继承关系的一个替代方案,Decorator不管装饰多少层,最后返回的还是Component; 装饰模式可以动态扩展一个类的功能。
使用场景:需要扩展一个类的功能;动态给一个对象增加功能,可以动态撤销;为一批兄弟类进行改装或加装功能;
12 策略模式
定义:定义一组算法,将每个算法封装起来,并且使它们之间可以互换。
三个角色:
Context 封装角色:上下文角色,起承上启下作用,屏蔽高层模块对策略、算法的直接访问。
Strategy 抽象策略角色:通常定义为接口,定义策略必须要有的方法。
ConcreteStrategy 具体策略。
public abstract Strategy{ public void proc(); public boolean accept(); } public Strategy1 extends Strategy { public void proc(){ } public boolean accept(){ return true; } } public Strategy2 extends Strategy { public void proc(){ } public boolean accept(){ return true; } } public class Context { private List<Strategy> list; public void proc(){ for(Strategy strategy : list){ if(strategy.accept()){ strategy.proc(); break; } } } }
优点:算法自由切换;避免多重条件判断
缺点:策略类数量增多;所有策略类都需要对外暴露
13 适配器模式
定义:将一个类的接口变成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作
目标角色 Target、原角色Adaptee、适配器角色Adapter
public interface Target{ public void request(); } public abstract Adaptee { public void request(){ } } publlic class Adapter extends Adaptee implements Target{ public void request(){ } }
14 迭代器模式
15 组合模式
定义:将对象组合成树形结构以表示“”部分-整体“的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
Component抽象构件角色:定义参加组合对象的共有方法跟属性,可以定义一些默认的行为
Leaf 叶子构件:叶子对象,其下再也没有其他的分支,也就是便利的最小单位。
Composite 树枝构件:作用是组合树枝节点和叶子节点形成一个树形结构。
public abstract class Component{ public void doSomething(); } public class Composite extends Component{ List <Component> componentList = new ArraysList<Component>(); public void add(Component obj) { componentList.add(obj); } public List<Component> getChildren(){ return componentList ; } } public class Leaf extends Component{ public void doSomething(){} } public class Client{ public static void main(String [] args){ Composite root = new Composite (); root.doSomething(); Composite branch= new Composite (); Leaf leaf = ne Leaf(); root.add(branch); branch.add(leaf); } }
优点:高层模块调用简单,节点自由组合
使用场景:维护跟展示部分-整体关系的场景
16 观察者模式
定义:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。
Subject 被观察者
Observer 观察者
优点:观察者与被观察者之间是抽象耦合、建立一套触发机制
场景: 关联行为场景,事件的多级出发场景,跨系统的消息交换场景,如消息队列的处理机制。
问题:广播链问题,观察者广播链在传播的过程中消息随时可变;异步处理问题,响应时长。
17 门面模式
又称外观模式,要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。
门面模式注重"统一的对象",也就是提供一个访问子系统的接口,除了这个接口不允许有任何访问子系统的行为发生。
Facade门面角色:客户端可以调用这个角色的方法。此角色知晓子系统的所有功能和责任
subsystem 子系统角色:可以同时有一个或多个子系统,子系统并不知道门面的存在,门面仅仅是另一个客户端。
优点:减少系统的相互依赖,提高灵活性,提高安全性。
场景:为一个复杂的模块或子系统提供一个供外界访问的接口、子系统相对独立(看做黑盒)
18 备忘录模式
19 访问者模式
20 状态模式
21 解释器模式
22 享元模式
23 桥梁模式