简单工厂、工厂方法、抽象工厂
简单工厂
通过定义多个factory.produceXXX()方法,或者通过向factory.produce(type)传递type参数来生成产品。
添加新产品需要添加produeXXX()方法或个性produce(type)来支持生成新的产品。工厂方法
一个Factory接口,接口中有一个produce()方法用于生成产品,具体的XXXFactory实现Factory接口并实现自己的produce()方法。
添加新产品时新增一个XXXFactory类,实现Factory接口并实现produce()方法。抽象工厂
一个Factory接口,接口中有多个produce()方法(produceA, produceB)每个方法对应生成一个类产品。
XXXFactory实现Factory接口,并实现其中的produce*()方法。抽象工厂与工厂方法的区别,可以理解为抽象工厂用于生产多个产品类,工厂方法只生产一个产品类。单例模式
保证一个类仅有一个实例,并提供一个静态的getInstance()方法获取这个实例。
懒汉式,不加锁,线程不安全
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; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
饿汉式,线程安全
public class Singleton {
private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; }
}
懒汉式,双重检查,线程安全
public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
懒汉式,静态内部类
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } }
通过枚举来实现单例
public enum Singleton { INSTANCE; public void whateverMethod() { } }
自由序列化,线程安全,保证单例。
建造者模式
独立的Builder类,通过build方法来生成实例。在build之前用add、set等一系列方法为将要生成的类设置属性值。可以参考protobuf的对象创建方法。
原型模式
复制现有实例生成新的实例。复制方式有深克隆与浅克隆之分,具体看clone()方法的实现。
适配器模式
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
例:AudioPlayer.play()能能播放MP3,现在要它能播放其他格式(例如aac),另一个AACPlayer可以播放aac格式。实现方法:1,创建一个MediaAdapter类,其中实例化一个AACPlayer用来播放aac格式2,MediaAdapter实现play方法来调用AACPlayer的play方法,以此来实现适配3,当用AudioPlayer播放aac格式时,调用MediaAdapter.play来间接调用AACPlayer的play方法4,要用AudioPlayer播放所有其他格式,都在MediaAdapter中做适配。桥模式
将抽象和实现放在两个不同的类层次中,使它们可以独立地变化。——《Head First 设计模式》
如何理解:Bridge.java
public interface Bridge { public void func(int radius, int x, int y);}
TheAbastractClass.java
public abstract class TheAbstractClass { protected Bridge bridge; protected TheAbstractClass(Bridge bridge){ this.bridge = bridge; } public abstract void func();}
BridgeOne.java
public class BridgeOne implements Bridge { @Override public void func() { System.out.println("BridgeOne.func called!"); }}
BridgeTwo.java
public class BridgeTwo implements Bridge { @Override public void func() { System.out.println("BridgeTwo.func called!"); }}
TheSpecificClass.java
public class TheSpecificClass extends TheAbastractClass{ TheSpecificClass(Bridge bridge){ super(bridge); } @override public void func(){ this.bridge.func(); }}
一般来说,直接继承TheAbstractClass来实现func方法。在桥模式下,继承TheAbstractClass之后,func方法的具体实现则在通过this.bridge实现的。
桥模式和适配器模式的区别可以看过滤器模式
类似函数式编程中的filter
组合模式
对象中包含对象,用实现树型结构,对单个对象和组合对象的使用具有一致性。
装饰模式
用于动态地给一个对象添加一些额外的职责。
例:Origin.javapublic interface Origin{ void func();}
OriginImpl.java
public class OriginImpl implements Origin{ public void func() { //do something }}
AbstactDecorator.java
public abstract class AbstractDecorator implements Origin{ protect Origin origin; public AbstractDecorator(Origin origin){ this.origin = origin; } public void func(){ this.origin.func(); }}
SpecificDecorator.java
public class SpecificeDecorator extends AbstractDecorator{ public SpecificDecorator(Origin origin){ super(origin); } @Override public void func(){ this.origin.func(); //do something else }}
main
public static int main(){ Origin origin = new SpecificeDecorator(new OriginImpl()); origin.func(); }
通过装饰器SpecificDecorator,可以在原来的OriginImpl.func()的基础上do something else
外观模式
用于隐藏系统的复杂性,提供一致的操作界面。
例如:1,ClassA, ClassB, ClassC三个类分别有methodA, methodB, methodC三个方法2,创建Facade类,关联ClassA, ClassB, ClassC,提供methodA, methodB, mehtodC3,通过Facade就可以调用mehtodA, methodB, methodC了享元模式
就是共享对象,将原来创建的对象保存起来,下次需要使用的时候优先使用已经创建过的相同对象。
代理模式
为其他对象提供一种代理以控制对这个对象的访问。
Origin.java
public interface Origin{ void func();}
OriginImpl.java
public class OriginImpl implements Origin{ public void func() { //do something }}
Proxy.java
public class Proxy implements Origin{ private Origin origin; public void func(){ if(origin == null){ origin = new OriginImpl(); } this.origin.func(); } }
Proxy为代理类,通过Proxy来间接的调用OriginImpl.func()
责任链模式
将请求的发送者和请求的处理者解耦。
当有多种类型(type)的Request,每个Request有一个指定的handler,通过把所有的handler连接起来形成一条链handlerLink。请求可以不用发送到指定的handler,直接发送到handlerLink,链中的每个handler判断type是不是自己的要处理的,如果不是则传递到下一个handler命令模式
对命令请求者(Invoker)和命令实现者(Receiver)的解耦,方便对命令进行各种控制。
ICommand: 命令接口,有execute方法
Command: 命令实现类 Invoker: 请求发送者 Receiver: 请求接收者,负责执行实际的业务逻辑不用命令模式:
想要调用Receiver的doSomething()方法Receiver r = new Receiver();r.doSomething()
命令模式:
Command.java
public Interface ICommand{ void execute();}public class Command implements ICommand{ private Receiver receiver; public Command(Receiver receiver){ this.receiver = receiver; } public void execute(){ receiver.doSomething(); }}
Invoker.java
public class Invoker{ ICommand cmd; public void setCommand(ICommand cmd){ this.cmd = cmd; } public void submit(){ this.cmd.execute(); }}
main
Invoker invoker = new Invoker();Receiver receiver = new Receiver();ICommand cmd = new Command(receiver);invoker.setCommand(cmd);invoder.submit();
命令模式实现Invoker与Receiver的隔离,Command与Receiver耦合。发送者只接收命令。当要扩展新的功能的时候,创建新的ICommand的实现类交给Invoker即可。
解释器模式
个人理解就是,解释器的作用就是把人能看明白的东西解释一下,让机器也看明白。比如,python代码是给人看的,python解释器就是把代码解释成机器能执行的指令;计算表达式(1+2+3*4/7)是人能看懂的,计算器的作用就是把计算表达式解释成能执行的一系列的简单运算。
代码和计算表达式这样的问题有几个重要的特征:
- 用什么元素来书写,在计算表达式中就是数字(0-9)和运算符(+-*/),在代码中就是字母、数字和符号
- 怎么书写(文法),在计算表达式中运算符和数字必须交替出现,在代码中就是各种语言和各自的语法规则。
所以,有规则可循的问题都可以用解释器模式来解决。但是将问题的规则提炼出来是很麻烦的,而且规则很复杂的时候更加难以提炼,成本很高。因此,只有当一类问题发生的频率足够高的情况下才适合用解释器模式。
迭代器模式
为不同的数据结构提供统一的顺序遍历的操作。
中介者模式
假设有ABCD四个对象,如果两两交互的话每个对象要维护三条链路。
加入中介,每个对象维护一条链路。备忘录模式
保存历史状态,以便可以恢复到原先的状态。
观察者模式
使用场景:一个对象A的改变要通知到一个或多个其他对象。
加入观察者可以让A不必关心具体要通知改变的其他对象,由观察者来发通知。
状态模式
类的行为是基于它的状态改变的,允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。如何理解这句话?
类(TheClass), 状态(State), 行为(action)
代码:
public class TheClass{ private State state; public void action(){ //TODO depends on state }}
TODO这块可以用switch case或者if else来实现,State一般是一个int
typedef int State;//状态一般是个整型public class TheClass{ private State state; public void setState(State state){ this.state = state; } public void action(){ switch (state) { case stateA: //do A; case stateB: //do B; } }}
不符合开闭原则,因为如果要增加一种状态,则需要修改代码,添加case
用状态模式,State是一个interface, 拥有一个action方法
public interface State{ void action();}public Class StateA implements State{ public void action(){ //do A }}public Class StateB implements State{ public void action(){ //do B }}public class TheClass{ private State state; public void setState(State state){ this.state = state; } public void action(){ this.state.action() }}
如果要添加一个C状态,只需要新建一个StateC实现State接口即可。
空对象模式
对象有方法,NULL什么都没有。空对象目的在于提供默认的方法。这样我们空对象执行相关操作时也不会报错。
策略模式
从输入获取输出可以有多种策略,例如排序问题就有插入、冒泡、快速、归并等不同和策略,都可以得到相同的结果。各种策略分别适用于特定的输入,例如,对于本身有序数组来说,冒泡策略只需要遍历一遍就可以。
如果用if else来解决排序问题:
sort(List list, Strategy strategy){ switch (strategy) { case insert: //do insert sort case bubble: //do bubble sort ... }}
不符合开闭原则,添加策略需要修改代码
用策略模式:
sort(List list, Strategy strategy){ strategy.sort(list)}
将策略抽象成接口,不同的策略实现该接口。
模板模式
一个操作operate,有多个step。我们把operate定义为固定的模板,各个step则可以重写。
public abstract class Template{ void step1(); void step2(); void step3(); void final operate(){ step1(); step2(); step3(); }}public class TheClass extends Template{ @override void step1(){ //do step1 } void step2(){ //do step2 } void step3(){ //do step3 }}
访问者模式
- 被访问者接口(Acceptor): 有accept(visitor)方法,接收visitor的访问
- 被访元素(AcceptorItem): 实现了Acceptor接口,通常不会直接暴露给Visitor。
- 访问者(Visitor): 有visit(acceptor)方法,访问acceptor元素
- 被访问对象(Containor): 直接暴露给Visitor出来的被访问对象,相当于一个Containor,以一定的结构组织了各个AcceptorItem。
Acceptor.java
public interface Acceptor{ void acceptor(Visitor visitor);}
Visitor.java
public interface Visitor{ void visit(AcceptorOne acceptor); void visit(AcceptorTwo acceptor);}
AcceptorOne.java
public class AcceptorOne extends{ public void accept(Visitor visitor){ visitor.visit(this); }}
AcceptorTwo.java
public class AcceptorTwo extends{ public void accept(Visitor visitor){ visitor.visit(this); }}
Containor.java
public class Containor implements Acceptor{ private Collectionacceptors; public void accept(Visitor visitor){ Iteratro it = acceptors.getIterator(); while(it.hasNext()){ visitor.visit(it.next()); } }}
访问者(Vistor)有多个visit方法,visit根据不同的Accepctor执行不同的逻辑。如果要扩展新的Acceptor,需要修改Visitor接口,这样不符合开闭原则;而扩展新的Visitor时,则只需要新增Visitor实现就可以了。因此,访问者模式适合对象结构稳定,而经常需要扩展对象操作的场景。
MVC模式
MVC模式是一种软件架构模式,应于交互式应用中。交互式应用就是界面+操作+数据后台。如果不使用MVC模式,界面的代码和对数据操作的代码杂在一起,不方便重用,也不容易维护。MVC模式分离了界面和数据,界面(View)通过控制器(Controller)提供的接口操作数据模型(Model),后台数据变更之后通过控制器通知到相关的界面。