文章目录
23种设计模式学习笔记
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。
1.创建型模式
创建型模式:对象实例化的模式,创建型模式用于解耦对象的实例化过程。
1 单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点,单例模式是关于怎样设计一个类,并使得该类只有一个实例的成熟模式,该模式的关键是将类的构造方法设置为private权限,并提供一个返回它的唯一实例的类方法。
代码:
package com.rfos.design;
/**
* 单例设计模式
* <p>
* 单例设计模式核心思想:私有构造方法,自己创建实例,对外提供获取实例方法。
* 1.饿汉式{@link LazySingleton}:
* 2.懒汉式{@link HungerSingleton}:
* </p>
*/
public class Singleton {
/**
* 饿汉式
*/
static class LazySingleton{
//创建实例
private static class Inner{
private static LazySingleton sSingleton = new LazySingleton();
}
//私有构造
private LazySingleton() {
}
//对外提供获取实例方法
public static LazySingleton getInstance() {
return Inner.sSingleton;
}
}
/**
* 懒汉式
*/
static class HungerSingleton{
private static HungerSingleton sSingleton = null;
private HungerSingleton() {
}
public static HungerSingleton getInstance() {
if (sSingleton == null) {
synchronized (HungerSingleton.class){
if (sSingleton == null) {
sSingleton = new HungerSingleton();
}
}
}
return sSingleton;
}
}
public static void main(String[] args) {
LazySingleton inner =LazySingleton.getInstance();
HungerSingleton hungerSingleton =HungerSingleton.getInstance();
}
}
2 工厂模式
工厂模式主要负责将大量有共同接口的类实例化,可以动态的决定创建哪一个类,而不事先知道要实例化具体哪一个类。
- 简单工厂模式:简单工厂模式是类的创建模式,又称为静态工厂方法,是有一个工厂的对象决定创建哪一类具体的产品。
- 工厂模式:工厂模式又成为动态工厂模式,由于静态工厂模式的缺点是,有新的类加入时需要修改工厂类代码,不符合开闭原则,因此引入类动态工厂模式,使用多态的方式去创建,具体创建类的过程交给子类去做,工厂和产品之间是一种平级的等级结构。
- 抽象工厂模式:抽象工厂模式是工厂模式中最具一般性的一种形态,提供一个创建一系列或相互依赖对象的接口,而无须制定他们具体的类。 它与工厂模式的最大区别是:工厂模式面对一个产品等级的结构,而抽象工厂模式面对多个产品等级结构。
代码:
package com.rfos.design.demo;
/**
* 工厂方法模式
* <p>
* 工厂方法模式主要分为三种:
* 1.普通工厂模式{@link FunctionCommonFactory}:建立一个工厂类,对实现了同一接口的类的实例创建,仅提供一个生产方法,根据不同标记位创建不同实例。
* 2.多个工厂模式{@link FunctionMoreFactory}:建立一个工厂类,对实现了同一接口的类的实例创建,提供创建不同实例的多个方法(对1的改进)。
* 3.静态工厂模式{@link FunctionStaticFactory}:建立一个工厂类,对实现了同一接口的类的实例创建,提供创建不同实例的多个静态方法(对2的改进)。
* </p>
*/
public class FactoryMethod {
/**
* 共同功能接口
*/
interface Function{
void play();
}
/**
* LOL游戏实现功能接口
*/
static class Lol implements Function{
@Override
public void play() {
System.out.println("Summoner! Please select your hero!");
}
}
/**
* 荒野行动游戏实现功能接口
*/
static class KnivesOut implements Function{
@Override
public void play() {
System.out.println("LYB");
}
}
/**
* 普通工厂类
*/
static class FunctionCommonFactory{
public static final int LOL = 0;
public static final int KNO = 1;
public Function produce(int flag) {
switch (flag) {
case LOL:
return new Lol();
case KNO:
return new KnivesOut();
}
return null;
}
}
/**
* 多个工厂类
*/
static class FunctionMoreFactory{
public Function produceLol() {
return new Lol();
}
public Function produceKno() {
return new KnivesOut();
}
}
/**
* 静态工厂类
*/
static class FunctionStaticFactory{
public static Function produceLol() {
return new Lol();
}
public static Function produceKno() {
return new KnivesOut();
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
commonFactory();
moreFactory();
staticFactory();
}
/**
* 静态工厂测试
*/
private static void staticFactory() {
Function lol = FunctionStaticFactory.produceLol();
Function kno = FunctionStaticFactory.produceKno();
lol.play();
kno.play();
}
/**
* 多个工厂测试
*/
private static void moreFactory() {
FunctionMoreFactory moreFactory = new FunctionMoreFactory();
Function lol = moreFactory.produceLol();
Function kno = moreFactory.produceKno();
lol.play();
kno.play();
}
/**
* 普通工厂测试
*/
private static void commonFactory() {
FunctionCommonFactory commonFactory = new FunctionCommonFactory();
Function lol = commonFactory.produce(FunctionCommonFactory.LOL);
Function kno = commonFactory.produce(FunctionCommonFactory.KNO);
lol.play();
kno.play();
}
}
3 抽象工厂模式
抽象工厂模式:抽象工厂模式是工厂模式中最具一般性的一种形态,提供一个创建一系列或相互依赖对象的接口,而无须制定他们具体的类。 它与工厂模式的最大区别是:工厂模式面对一个产品等级的结构,而抽象工厂模式面对多个产品等级结构。
package com.rfos.design.demo;
/**
* 抽象工厂模式(对工厂方法模式的改进)
* <p>
* 工厂方法模式有一个问题就是,类的创建依赖工厂类,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则;所以,从设计角度考虑,有一定的问题。
* 而抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
* </p>
*/
public class AbstractFactory {
/**
* 共同功能接口
*/
interface Function{
void play();
}
/**
* 工厂共同生产接口
*/
interface Provider {
Function produce();
}
/**
* LOL游戏实现功能接口
*/
static class Lol implements Function {
@Override
public void play() {
System.out.println("Summoner! Please select your hero!");
}
}
/**
* 荒野行动游戏实现功能接口
*/
static class KnivesOut implements Function {
@Override
public void play() {
System.out.println("LYB");
}
}
/**
* LOL工厂类
*/
static class LolFactory implements Provider{
@Override
public Function produce() {
return new Lol();
}
}
/**
* KNO工厂类
*/
static class KnoFactory implements Provider{
@Override
public Function produce() {
return new KnivesOut();
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
LolFactory lolFactory = new LolFactory();
lolFactory.produce().play();
KnoFactory knoFactory = new KnoFactory();
knoFactory.produce().play();
}
}
4 建造者模式
将一个复杂的对象的构建与他的表示进行分离,使用同样的构建过程但可以创建不同的表示。
package com.rfos.design.demo;
/**
* 建造者模式
* <p>
* 建造者模式是将各种产品集中起来进行管理,用来创建复合对象。
* </p>
*/
public class BuilderDemo {
static class Color{
}
static class Context{
}
protected static class DialogController{
Color mColor;
Context mContext;
}
/**
* 目标类
*/
static class Dialog{
private Context mContext;
private Color mColor;
protected Dialog(Context context) {
mContext = context;
}
public void setColor(Color color) {
mColor = color;
}
public void show() {
System.out.println("Dialog show!");
}
/**
* 建造者类
*/
static class Builder{
private DialogController mDialogController = null;
public Builder(Context context) {
mDialogController = new DialogController();
mDialogController.mContext = context;
}
public Builder setColor(Color color) {
mDialogController.mColor = color;
return this;
}
public Dialog build() {
Dialog dialog = new Dialog(mDialogController.mContext);
if (mDialogController.mColor != null) {
dialog.setColor(mDialogController.mColor);
}
return dialog;
}
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
Dialog dialog = new Dialog.Builder(new Context())
.setColor(new Color())
.build();
dialog.show();
}
}
5 原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是从一个对象出发得到一个和自己有相同状态的新对象的成熟模式,该模式的关键是将一个对象定义为原型,并为其提供复制自己的方法。
package com.rfos.design.demo;
import java.io.*;
/**
* 原型模式
* <p>
* 原型模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。
* </p>
*/
public class Prototype implements Cloneable, Serializable {
class SerializableObject implements Serializable {
private static final long serialVersionUID = 1L;
}
private static final long serialVersionUID = 1L;
private String string;
private SerializableObject obj;
/* 浅复制 */
public Object clone() throws CloneNotSupportedException {
return (Prototype) super.clone();
}
/* 深复制 */
public Object deepClone() throws IOException, ClassNotFoundException {
/* 写入当前对象的二进制流 */
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
/* 读出二进制流产生的新对象 */
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
public SerializableObject getObj() {
return obj;
}
public void setObj(SerializableObject obj) {
this.obj = obj;
}
}
2.结构型模式
结构型模式:把类或对象结合在一起形成一个更大的结构。
6 代理模式
为其他对象提供一种代理以控制对这个对象的访问。
代理模式是为对象提供一个代理,代理可以控制对它所代理的对象的访问。
代理模式最常见的两种情况:远程代理和虚拟代理。
结构
- 抽象主题(Subject) 该接口是对象和它的代理共同的接口。
- 实际主题(RealSubject) 实际主题是实现抽象主题接口的类,是代理角色实例所要代理的对象。
- 代理(Proxy) 是实现抽象主题接口的类,可以控制对他所包含的角色的实例的访问。
package com.rfos.design.demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 代理模式
* <p>
* 代理模式与装饰模式类似,都持有待操作类的对象,但装饰模式一般在编译时不明确待装饰对象,并且一般是增强待装饰对象的功能;而代理模式一般是在编译时就明确了
* 编译对象(内部创建待代理对象),主要用于限制访问,不暴露真实对象。
* </p>
*/
public class Proxy {
interface InputStream{
void read();
}
interface OutputStream{
void write(byte b);
}
static class FileInputStream implements InputStream{
@Override
public void read() {
System.out.println("File read");
}
}
static class FileOutputStream implements OutputStream{
@Override
public void write(byte b) {
System.out.println("File write");
}
}
/**
* 静态代理模式
*/
static class FileProxy implements InputStream, OutputStream{
private InputStream mInputStream;
private OutputStream mOutputStream;
public FileProxy() {
mInputStream = new FileInputStream();
mOutputStream = new FileOutputStream();
}
@Override
public void read() {
System.out.println("限制条件");
mInputStream.read();
}
@Override
public void write(byte b) {
System.out.println("限制条件");
mOutputStream.write(b);
}
}
/**
* 动态代理模式(Java自带动态代理机制)
*/
static class DynamicProxy implements InvocationHandler{
private OutputStream mOutputStream;
public DynamicProxy(OutputStream outputStream) {
mOutputStream = outputStream;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(mOutputStream, args);
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
FileProxy proxy = new FileProxy();
proxy.read();
proxy.write((byte) 0x01);
DynamicProxy dynamicProxy = new DynamicProxy(new FileOutputStream());
OutputStream outputStream = (OutputStream) java.lang.reflect.Proxy.newProxyInstance(dynamicProxy.getClass().getClassLoader(), new
Class[]{OutputStream.class}, dynamicProxy);
outputStream.write((byte) 0x02);
}
}
7 适配器模式
适配器模式就是将一个类的接口转换成客户希望的另一个接口的过程,能够使得原来不兼容的对象一起工作
结构如下
-
目标Target: 目标是一个接口,该接口是客户想要的接口
-
被适配者Adaptee: 被适配者是一个已经存在的接口或者抽象类,需要进行适配
-
适配器Adapter: 适配器是一个类,职责是对适配者的接口进行适配
package com.rfos.design.demo; /** * 适配器模式 * <p> * 适配器模式主要分为三种: * 1.类的适配器模式{@link AdapterClass}:有一个{@link Source}类,拥有一个方法,待适配,目标接口是{@link Target},通过{@link AdapterClass}类, * 将Source的功能扩展到Target里。 * 2.对象的适配器模式{@link AdapterObject}:适配器类AdapterObject持有待适配类Source的引用,实现适配目标接口Target,调用待适配类Source的方法, * 可以解决兼容性问题(方法不一致性)。 * 3.接口的适配器模式{@link AdapterInterface}:在实际开发中,接口{@link DownloadListener}中定义了太多的方法,我们在一些实现类中并不是都需要, * 则可以适配该接口。 * </p> */ public class Adapter { /** * 待适配类 */ static class Source{ public void method1() { System.out.println("Source method1"); } } /** * 适配目标接口 */ interface Target{ void method1(); void method2(); } /** * 适配器类(类的适配器模式) */ static class AdapterClass extends Source implements Target{ @Override public void method2() { System.out.println("Target method2"); } } /** * 适配器类(对象的适配器模式) */ static class AdapterObject implements Target{ private Source mSource; public AdapterObject(Source source) { mSource = source; } @Override public void method1() { mSource.method1(); } @Override public void method2() { System.out.println("Target method2"); } } /** * 待适配接口(接口的适配器模式) */ interface DownloadListener{ void onPre(); void onStart(); void onProgress(int progress); void onSuccess(); void onError(); void onCompleted(); } /** * 抽象类空实现接口(接口的适配器模式) */ static abstract class SimpleDownloadListener implements DownloadListener{ @Override public void onPre() { } @Override public void onStart() { } @Override public void onProgress(int progress) { } @Override public void onSuccess() { } @Override public void onError() { } @Override public void onCompleted() { } } /** * 适配接口,实现所需方法(接口的适配器模式) */ static class AdapterInterface extends SimpleDownloadListener{ @Override public void onProgress(int progress) { System.out.println("Progress: " + progress); } } }
8 桥接模式
将抽象部分与它的实现部分分离,使得它们都可以独立地变化。
桥接模式是关于怎样将抽象部分与它的实现部分分离,使得它们都可以独立地变化的成熟模式。
结构
- 抽象(Abstraction) 是一个抽象类,含有Implementor声明的变量,即维护一个Implementor类型的对象
- 实现者(Implementor) 是一个接口,该接口中的方法不一定与Abstraction中的方法一致。Implementor负责定义基本操作,Abstraction负责定义高级操作
- 细化抽象(Refined Abstraction) 是抽象角色的一个子类,该子类在重写抽象角色的方法是,给出一些必要的操作以后,将委托所维护的Implementor类型调用相应的方法
- 具体实现者(Concrete Implementor) 是扩展Implementor接口的类
package com.rfos.design.demo;
/**
* 桥接模式
* <p>
* 桥接的用意是:将抽象化与实现化解耦,使得二者可以独立变化,功能的调用基本不变。
* </p>
*/
public class Bridge {
/**
* 桥接资源接口
*/
interface Source{
void method();
}
/**
* 桥接资源的第一种实现
*/
static class FirstSource implements Source{
@Override
public void method() {
System.out.println("First");
}
}
/**
* 桥接资源的第二种实现
*/
static class SecondSource implements Source{
@Override
public void method() {
System.out.println("Second");
}
}
/**
* 桥接资源的桥
*/
static abstract class BridgeSource{
private Source mSource;
protected Source getSource() {
return mSource;
}
public void setSource(Source source) {
mSource = source;
}
public abstract void method();
}
/**
* 桥的管理类
*/
static class BridgeManage extends BridgeSource{
@Override
public void method() {
getSource().method();
}
}
/**
* 测试 客户启用功能
* @param args
*/
public static void main(String[] args) {
BridgeManage manage = new BridgeManage();
Source source1 = new FirstSource();
manage.setSource(source1);
manage.method();
Source source2 = new SecondSource();
manage.setSource(source2);
manage.method();
}
}
9 装饰模式
装饰模式是动态的扩展一个类的功能,而不需要改变原始类的代码。
结构
主要包含四个角色:
- 抽象组建:抽象组建是一个抽象类,定义了被装饰者需要装饰的方法
- 具体组建:是抽象组建的一个子类,具体组建的实例成为“被装饰者”
- 装饰Decorator: 装饰者可以是一个抽象类也可以是一个非抽象类,是抽象组建的一个子类,但是还包含抽象组建的一个变量以保存“被装饰者”的引用。
- 具体装饰:是一个非抽象的子类,具体装饰的实例被称为“装饰者”
package com.rfos.design.demo;
/**
* 装饰模式
* <p>
* 装饰模式可以扩展一个类的功能,动态的为一个对象增加功能,还能动态的撤销。
* </p>
*/
public class Decorator {
/**
* 装饰接口
*/
interface Source{
void method();
}
/**
* 待装饰实现类
*/
static class SourceImpl implements Source{
@Override
public void method() {
System.out.println("Source something");
}
}
/**
* 装饰类
*/
static class DecoratorSource implements Source{
private Source mSource;
public DecoratorSource(Source source) {
mSource = source;
}
@Override
public void method() {
System.out.println("Decorator before source");
mSource.method();
System.out.println("Decorator after source");
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
Source source = new DecoratorSource(new SourceImpl());
source.method();
}
}
10 外观模式
为系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得子系统更加容易使用
结构
-
子系统:子系统是由若干个类组成的集合,这些类的实例协同合作为用户提供所需要的功能,子系统中的任何类都不包含外观类的实例引用
-
外观:外观是一个类,该类包含子系统中全部或者部分类的实例引用,当用户需要和子系统的实例打交道的时候,可以代替得和子系统的外观实例打交道
-
package com.rfos.design.demo; /** * 外观模式 * <p> * 外观模式是为了解决类与类之间的依赖关系,像spring一样,可以将类和类之间的关系配置到配置文件中, * 而外观模式就是将他们的关系放在一个Facade类中,降低了类类之间的耦合度,该模式中没有涉及到接口。 * </p> */ public class Facade { static class First{ String start() { System.out.println("Start game"); return "ready"; } } static class Second{ void ready(String str){ System.out.println("Init has completed:" + str); } } static class Third{ void play() { System.out.println("Come on!"); } } /** * 外观包装类 */ static class FacadeClass{ private First mFirst; private Second mSecond; private Third mThird; public FacadeClass() { mFirst = new First(); mSecond = new Second(); mThird = new Third(); } public void playGame() { String start = mFirst.start(); mSecond.ready(start); mThird.play(); } } /** * 测试 客户使用 * @param args */ public static void main(String[] args) { FacadeClass facadeClass = new FacadeClass(); facadeClass.playGame(); } }
11 组合模式
将对象组合成数形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
组合模式是关于怎样将对象形成树形结构来表现整体和部分的层次结构的成熟模式。使用组合模式,可以让用户以一致的方式处理个体对象和组合对象。
组合模式的关键在于无论是个体对象还是组合对象都实现了相同的接口或都是同一个抽象类的子类。
结构
抽象组件Component: 定义了个体对象和组合对象需要实现的关于操作其子节点的方法 Composite节点Composite Node: 实现了Component接口,也可以包含其他Composite节点或者Leaf节点的引用 Leaf节点Leaf Node: 实现Composite接口类的实例
package com.rfos.design.demo;
/**
* 组合模式
* <p>
* 组合模式有时又叫 部分-整体 模式,在处理类似树形结构的问题时比较方便。
* </p>
*/
public class Composite {
/**
* 外部整体类
* @param <T>
*/
static class Tree<T>{
private TreeNode<T> root;
private TreeNode<T> point;
private int size;
public void add(T data) {
TreeNode<T> node = new TreeNode<>(data);
if (root == null) {
root = node;
point = node;
}else {
point.add(node);
point = node;
}
size++;
}
public boolean remove(T data) {
TreeNode<T> temp = root;
while (temp != null) {
if (temp.data == data) {
if (temp.equals(root)) {
root = temp.next;
}
temp.remove();
size--;
return true;
}
temp = temp.next;
}
return false;
}
public int size() {
return size;
}
public void print() {
TreeNode<T> temp = root;
while (temp != null) {
System.out.println(temp.data);
temp = temp.next;
}
}
/**
* 内部节点类
* @param <T>
*/
static class TreeNode<T>{
private T data;
private TreeNode<T> pre;
private TreeNode<T> next;
private TreeNode(T data) {
this.data = data;
}
private void add(TreeNode node) {
next = node;
node.pre = this;
}
private void remove() {
if (pre != null) {
pre.next = next;
}
if (next != null) {
next.pre = pre;
}
pre = null;
next = null;
data = null;
}
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
Tree<String> tree = new Tree<>();
boolean a = tree.remove("a");
System.out.println(a);
System.out.println(tree.size());
tree.add("a");
tree.add("b");
tree.add("c");
tree.add("d");
tree.print();
System.out.println(tree.size());
tree.remove("a");
tree.remove("c");
tree.print();
System.out.println(tree.size());
}
}
12 享元模式
运用共享技术有效地支持大量细粒度的对象。
一个类中的成员变量表明该类所创建的对象所具有的属性,在某些程序设计中我们可能用一个类创建若干个对象,但是我们发现这些对象的一个共同特点是它们有一部分属性的取值必须是完全相同的。
结构
- 享元接口(Flyweight):定义了享元对外公开数据的方法和接收外部数据的方法
- 具体享元(Concrete Flyweight): 保证使用享元对象的应用程序无法修改享元内部的数据,因为要保证享元对象是共享的,创建和管理享元对象必须由享元工厂负责
- 享元工厂(Flyweight Factory):负责创建和管理享元对象,可以采用单例模式进行设计
package com.rfos.design.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Vector;
/**
* 享元模式
* <p>
* 享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。
* </p>
*/
public class Flyweight {
/**
* 连接池
*/
static class ConnectionPool{
private Vector<Connection> mPool;
private String url = "jdbc:mysql://localhost:3306/test";
private String driverClassName = "com.mysql.jdbc.Driver";
private String account = "root";
private String password = "123456";
private int poolSize = 50;
private Connection con;
public ConnectionPool() {
mPool = new Vector<>();
for (int i = 0; i < poolSize; i++) {
try {
Class.forName(driverClassName);
Connection connection = DriverManager.getConnection(url, account, password);
mPool.add(connection);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public synchronized void release() {
mPool.add(con);
con = null;
}
public synchronized Connection getConnection() {
if (mPool.size() > 0) {
con = mPool.get(0);
mPool.remove(con);
return con;
}
return null;
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
ConnectionPool pool = new ConnectionPool();
Connection connection = pool.getConnection();
System.out.println(connection);
}
}
3.行为型模式
行为型模式:类和对象如何交互,及划分责任和算法。
13 策略模式
定义一系列算法,把他们封装起来,并且他们可以互相替换,可以独立于使用它的客户端而变换。该模式的核心就是将经常需要变化的类抽离出来,将每一种可能的变化对应的交给抽象类或接口的子类去实现。
基本概念
策略:封装算法标识的接口是策略 具体策略:实现接口的策略是具体策略 上下文:依赖于策略接口的类
package com.rfos.design.demo;
/**
* 策略模式
* <p>
* 策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。
* 策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。
* 策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可
* </p>
*/
public class Strategy {
/**
* 计算接口
*/
interface ICalculator{
int calculate(String expression);
}
/**
* 辅助计算类
*/
static abstract class Assist{
protected int[] split(String exp, String regex) {
String[] split = exp.split(regex);
int[] ints = new int[2];
ints[0] = Integer.parseInt(split[0]);
ints[1] = Integer.parseInt(split[1]);
return ints;
}
}
/**
* 加法运算
*/
static class Plus extends Assist implements ICalculator{
@Override
public int calculate(String expression) {
int[] ints = split(expression, "\\+");
return ints[0] + ints[1];
}
}
/**
* 减法运算
*/
static class Minus extends Assist implements ICalculator{
@Override
public int calculate(String expression) {
int[] ints = split(expression, "-");
return ints[0] - ints[1];
}
}
/**
* 乘法运算
*/
static class Multiply extends Assist implements ICalculator{
@Override
public int calculate(String expression) {
int[] ints = split(expression, "\\*");
return ints[0] * ints[1];
}
}
/**
* 除法运算
*/
static class Division extends Assist implements ICalculator{
@Override
public int calculate(String expression) {
int[] ints = split(expression, "\\/");
return ints[0] / ints[1];
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
System.out.println(new Plus().calculate("10+20"));
System.out.println(new Minus().calculate("100-55"));
System.out.println(new Multiply().calculate("11*22"));
System.out.println(new Division().calculate("999/67"));
}
}
14 观察者模式
官方解释:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖的对象能够得到通知并自动更新。
观察者模式是关于一个对象想知道另一个对象中数据变化情况的一种成熟的模式。观察者模式中存在“主题”和若干个“观察者”,把“主题”中变化的东西抽离出来,当发生变化时,所有的“观察者”能够得到通知。
应用场景
很多消息中间件是采用这种观察者模式,Java并发编程中异步回调的方式也类似于观察者模式。
角色分析
- 主题:主题是一个接口,该接口规定了具体主题需要实现的方法;
- 观察者:观察者是一个接口,该接口规定了具体观察者用来更新数据的方法;
- 具体主题:具体主题是实现主题接口的一个实例;
- 具体观察者:是实现观察者接口的一个实例;
package com.rfos.design.demo;
import javax.security.auth.Subject;
import java.util.Vector;
/**
* 观察者模式
* <p>
* 观察者模式即监听模式,描述类与类之间的关系,主要是在目标类中注册监听器,当目标类的有效值实时改变时,通过监听器及时回调通知各个注册者。
* </p>
*/
public class Observer {
/**
* 观察者接口
*/
interface IObserver{
void update(String data);
}
/**
* 注册接口
*/
interface Subject{
/**
* 增加观察者
* @param observer
*/
void add(IObserver observer);
/**
* 删除观察者
* @param observer
*/
void del(IObserver observer);
/**
* 通知更新
*/
void notifyObservers();
/**
* 自身操作
*/
void operation();
}
/**
* 抽象注册接口
*/
static abstract class AbstractSubject implements Subject {
private Vector<IObserver> mObservers = new Vector<>();
@Override
public void add(IObserver observer) {
mObservers.add(observer);
}
@Override
public void del(IObserver observer) {
mObservers.remove(observer);
}
@Override
public void notifyObservers() {
for (IObserver observer : mObservers) {
observer.update("Hello World");
}
}
}
/**
* 注册实现
*/
static class SubjectImpl extends AbstractSubject{
@Override
public void operation() {
notifyObservers();
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) throws InterruptedException {
SubjectImpl subject = new SubjectImpl();
subject.add(System.out::println);
subject.add(System.out::println);
Thread.sleep(1000);
subject.operation();
}
}
15 责任链模式
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象形成一条链,并沿着这条链传递该请求,知道有一个对象处理它为止
结构
处理者Handler: 处理者是一个接口,负责规定具体处理者处理用户请求的方法以及具体处理者设置后继对象的方法
具体处理者ConcreteHandler:实现处理者接口的实例,处理者通过调用处理者接口的规定方法处理用户的请求,如果能处理则处理,否则反馈无法处理的信息给用户
package com.rfos.design.demo;
/**
* 责任链模式
* <p>
* 责任链模式:有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。
* 但是发出者并不清楚到底最终哪个对象会处理该请求,所以,责任链模式可以实现,在隐瞒客户端的情况下,对系统进行动态的调整。
* </p>
*/
public class ChainResponse {
/**
* 功能接口
*/
interface Chain{
void operate();
}
/**
* 加工类
*/
static class AbstractChain{
private Chain mChain;
public Chain getChain() {
return mChain;
}
public void setChain(Chain chain) {
mChain = chain;
}
}
/**
* 实现类
*/
static class ManageChain extends AbstractChain implements Chain{
private String mName;
public ManageChain(String name) {
mName = name;
}
@Override
public void operate() {
System.out.println("Hello "+mName);
if (getChain() != null) {
getChain().operate();
}
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
ManageChain chain1 = new ManageChain("Chain1");
ManageChain chain2 = new ManageChain("Chain2");
ManageChain chain3 = new ManageChain("Chain3");
chain1.setChain(chain2);
chain2.setChain(chain3);
chain1.operate();
}
}
16 模板模式
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法是关于怎样将若干个方法集成到一个方法中,以便形成一个解决问题的算法骨架。模板方法模式的关键是在一个抽象类中定义一个算法的骨架,即将若干个方法集成到一个方法中,并称该方法为一个模板方法,或简称为模板。
结构
- 抽象模板(Abstract Template)抽象模板是一个抽象类,定义了若干个抽象的方法,以表示一个算法的各个步骤,抽象方法成为原语操作。
- 具体模板(Concrete Template)具体模板是抽象模板的子类,实现抽象模板中的原语操作
package com.rfos.design.demo;
/**
* 模板方法模式
* <p>
* 模板方法模式主要是创建一个抽象类,其中包含模板方法(主方法),而类中其他方法均由主方法调配,子类可以根据自己的特性重写其他方法,从而达到需求。
* </p>
*/
public class TemplateMethod {
/**
* 模板类
*/
static abstract class AbstractCalculator {
/*主方法,实现对本类其它方法的调用*/
public final int calculate(String exp,String opt){
int array[] = split(exp,opt);
return calculate(array[0],array[1]);
}
/*被子类重写的方法*/
abstract public int calculate(int num1,int num2);
public int[] split(String exp,String opt){
String array[] = exp.split(opt);
int arrayInt[] = new int[2];
arrayInt[0] = Integer.parseInt(array[0]);
arrayInt[1] = Integer.parseInt(array[1]);
return arrayInt;
}
}
/**
* 实现类 加法运算
*/
static class Plus extends AbstractCalculator {
@Override
public int calculate(int num1,int num2) {
return num1 + num2;
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
AbstractCalculator calculator = new Plus();
int calculate = calculator.calculate("998+98", "\\+");
System.out.println(calculate);
}
}
17 状态模式
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
一个对象的状态依赖于它的变量的取值情况,对象在不同的运行环境中,可能具有不同的状态。在许多情况下,对象调用方法所产生的行为效果依赖于它当时的状态。
状态模式的关键是将对象的状态封装成为独立的类,对象调用方法时,可以委托当前对象所具有的状态调用相应的方法,使得当前对象看起来好像修改了它的类。
结构
- 环境(Context) 环境是一个类,该类含有抽象状态声明的变量,可以引用任何具体状态类的实例,用户对该环境类的实例在某个状态下的行为感兴趣
- 抽象状态(State) 抽象状态是一个接口或者抽象类,抽象状态中定义了与环境的一个特定状态相关的若干个方法
- 具体状态(Concrete State)具体状态是实现抽象状态的类
package com.rfos.design.demo;
/**
* 状态模式
* <p>
* 核心思想就是:当对象的状态改变时,同时改变其行为。
* </p>
*/
public class StateDemo {
/**
* 状态类
*/
static class State{
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public void method1() {
System.out.println("state1 do something");
}
public void method2() {
System.out.println("state2 do something");
}
}
/**
* 状态行为切换类
*/
static class Context{
private State mState;
public State getState() {
return mState;
}
public void setState(State state) {
mState = state;
}
public Context(State state) {
mState = state;
}
public void method() {
switch (mState.value) {
case "state1":
mState.method1();
break;
case "state2":
mState.method2();
break;
}
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
State state = new State();
Context context = new Context(state);
state.setValue("state1");
context.method();
state.setValue("state2");
context.method();
}
}
18 访问者模式
表示一个作用于某对象结构中的各个元素的操作。它使你可以在不改变各个元素的类的前提下定义作用于这些元素的新操作。
当一个集合中有若干个对象时,习惯上将这些对象称作集合中的元素,访问者模式可以使得我们在不改变集合中各个元素的类的前提下定义作用于这些元素上的新操作。
结构
- 抽象元素(Element) :抽象类定义了接收访问者的accept操作
- 具体元素(Concrete Element) :Element的子类
- 对象结构(Object Structure) :一个集合,用于存放Element对象,提供了遍历它自己的方法
- 抽象访问者(Visitor) :一个接口,定义了操作对象(Concrete Element) 的方法
- 具体访问者(Concrete Visitor) 实现Visitor接口的类
package com.rfos.design.demo;
/**
* 访问者模式
* <p>
* 访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式适用于数据结构相对稳定算法又易变化的系统。
* 因为访问者模式使得算法操作增加变得容易。若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。
* 访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者。
* 访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统数据结构。其缺点就是增加新的数据结构很困难。
* </p>
*/
public class VisitorDemo {
/**
* 访问者接口
*/
interface Visitor{
void visit(Subject subject);
}
/**
* 被访问者
*/
interface Subject{
void accept(Visitor visitor);
String getSubject();
}
/**
* 访问者实现类
*/
static class VisitorImpl implements Visitor{
@Override
public void visit(Subject subject) {
System.out.println(subject.getSubject());
}
}
/**
* 被访问者实现类
*/
static class SubjectImpl implements Subject{
private String value;
public SubjectImpl(String value) {
this.value = value;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String getSubject() {
return value;
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
Visitor visitor = new VisitorImpl();
Subject subject = new SubjectImpl("Hello Visitor");
subject.accept(visitor);
}
}
19.备忘录模式
表示一个作用于某对象结构中的各个元素的操作。它使你可以在不改变各个元素的类的前提下定义作用于这些元素的新操作。
备忘录模式是关于怎样保存对象状态的成熟模式,其关键是提供一个备忘录对象,该备忘录负责存储一个对象的状态,程序可以在磁盘或内存中保存这个备忘录,这样一来,程序就可以根据对象的备忘录将该对象恢复到备忘录中所存储的状态。
结构
-
原发者(Originator) 需要在某个时刻保存其状态的对象。负责创建备忘录,然后使用该备忘录记录自己的状态
-
备忘录(Memento) 负责存储原发者状态的对象
-
负责人(Caretaker) 负责管理保存备忘录的对象,可以通过使用对象流将备忘录写入文件
-
package com.rfos.design.demo; /** * 备忘录模式 * <p> * 备忘录模式的主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象。 * </p> */ public class MementoDemo { /** * 备忘录类 */ static class Memento{ private String value; public String getValue() { return value; } public void setValue(String value) { this.value = value; } public Memento(String value) { this.value = value; } } /** * 原始类 */ static class Original{ private String value; public String getValue() { return value; } public void setValue(String value) { this.value = value; } public Original(String value) { this.value = value; } public Memento createMemento() { return new Memento(value); } public void restoreMemento(Memento memento) { this.value = memento.value; } } /** * 备忘录存储类 */ static class Storage{ private Memento mMemento; public Memento getMemento() { return mMemento; } public void setMemento(Memento memento) { mMemento = memento; } public Storage(Memento memento) { mMemento = memento; } } /** * 测试 * @param args */ public static void main(String[] args) { Original original = new Original("你好"); System.out.println("1."+original.getValue()); Storage storage = new Storage(original.createMemento()); original.setValue("不好"); System.out.println("2."+original.getValue()); original.restoreMemento(storage.getMemento()); System.out.println("3."+original.getValue()); } }
20.中介者模式
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使耦合松散,而且可以独立的改变他们之间的交互
结构
-
中介者Mediator:中介者是一个接口,用于定义同事对象之间通信的方法
-
具体中介者ConcreteMediator: 需要包含所有具体同事的引用
-
同事Colleague: 一个接口,规定了具体同事需要实现的方法
-
具体同事ConcreteColleague: 实现同事接口的类,只需要将具体的请求通知给包含他的中介者即可
-
package com.rfos.design.demo; /** * 中介者模式 * <p> * 中介者模式是用来降低类类之间的耦合的,因为如果类类之间有依赖关系的话,不利于功能的拓展和维护,因为只要修改一个对象,其它关联的对象都得进行修改。 * 如果使用中介者模式,只需关心和Mediator类的关系,具体类类之间的关系及调度交给Mediator就行,这有点像spring容器的作用。 * </p> */ public class MediatorDemo { /** * 中介者接口 */ interface Mediator { void createMediator(); void workAll(); } /** * 用户抽象类 */ static abstract class User { private Mediator mMediator; public Mediator getMediator() { return mMediator; } public User(Mediator mediator) { mMediator = mediator; } public abstract void work(); } /** * 用户1 */ static class User1 extends User { public User1(Mediator mediator) { super(mediator); } @Override public void work() { System.out.println("User1 do something"); } } /** * 用户2 */ static class User2 extends User { public User2(Mediator mediator) { super(mediator); } @Override public void work() { System.out.println("User2 do something"); } } /** * 中介者实现类 */ static class MediatorImpl implements Mediator { private User1 mUser1; private User2 mUser2; public User1 getUser1() { return mUser1; } public User2 getUser2() { return mUser2; } @Override public void createMediator() { mUser1 = new User1(this); mUser2 = new User2(this); } @Override public void workAll() { mUser1.work(); mUser2.work(); } } /** * 测试 * @param args */ public static void main(String[] args) { Mediator mediator = new MediatorImpl(); mediator.createMediator(); mediator.workAll(); } }
21. 迭代器模式
提供一种方法可以顺序访问一个聚合对象中的各个元素,而又不需要暴露对象的内部表示
结构
-
集合Aggregate:一个接口,规定了集合需要实现的操作
-
具体集合ConcreteAggregate:实现集合接口的具体实例,按照一定的结构存储对象,具体集合应该有一个方法,返回针对该集合的迭代器
-
迭代器Iterator:一个接口,规定了遍历具体集合的方法,比如next()方法
-
具体迭代器ConcreteIterator: 实现迭代器接口的具体实例
-
package com.rfos.design.demo; /** * 迭代器模式 * <p> * 迭代器模式就是顺序访问聚集中的对象,这句话包含两层意思:一是需要遍历的对象,即聚集对象,二是迭代器对象,用于对聚集对象进行遍历访问。 * </p> */ public class IteratorDemo { /** * 迭代器接口 */ interface Iterator{ Object pre(); Object next(); boolean hasNext(); Object first(); } /** * 集合接口 */ interface Collection{ Iterator iterator(); Object get(int i); int size(); } /** * 迭代器实现类 */ static class IteratorImpl implements Iterator{ private Collection mCollection; private int pos = -1; public IteratorImpl(Collection collection) { mCollection = collection; } @Override public Object pre() { if (pos > 0) { pos--; } return mCollection.get(pos); } @Override public Object next() { if (pos < mCollection.size() - 1) { pos++; } return mCollection.get(pos); } @Override public boolean hasNext() { return pos < mCollection.size() - 1; } @Override public Object first() { pos = 0; return mCollection.get(pos); } } /** * 集合实现类 */ static class CollectionImpl implements Collection{ public String[] mStrings = {"a", "b", "c", "d", "e", "f", "g"}; @Override public Iterator iterator() { return new IteratorImpl(this); } @Override public Object get(int i) { return mStrings[i]; } @Override public int size() { return mStrings.length; } } /** * 测试 * @param args */ public static void main(String[] args) { Collection collection = new CollectionImpl(); Iterator iterator = collection.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } }
22 解析器模式
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
结构
- 抽象表达式(AbstractExpression) 负责定义抽象的解释角色
- 终结符表达式子(TerminalExpression) 实现AbstractExpression接口,该类将接口中的解释操作实现为与文法中的终结符相关联的操作
- 非终结符表达式子(NonterminalExpression) 实现AbstractExpression的类,为文法的非终结符实现解释操作
- 上下文(Context) 包含解释器之外的一些全局信息
package com.rfos.design.demo;
/**
* 解释器模式
* <p>
* 解释器模式一般主要应用在OOP开发中的编译器的开发中。
* </p>
*/
public class Interpreter {
/**
* 上下文
*/
static class Context{
private int num1;
private int num2;
public int getNum1() {
return num1;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
public Context(int num1, int num2) {
this.num1 = num1;
this.num2 = num2;
}
}
/**
* 表达式接口
*/
interface Expression{
int interpret(Context context);
}
/**
* 加法解释器
*/
static class Plus implements Expression{
@Override
public int interpret(Context context) {
return context.getNum1() + context.getNum2();
}
}
/**
* 减法解释器
*/
static class Minus implements Expression{
@Override
public int interpret(Context context) {
return context.getNum1() - context.getNum2();
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
//998-668+1080
int interpret = new Plus().interpret(new Context(new Minus().interpret(new Context(998, 668)), 1080));
System.out.println(interpret);
}
}
23 命令模式
将一个请求封装为一个对象,从而使用户可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。
结构
主要包含四个角色
- 接收者Receiver:接收者是一个类的实例,负责执行与请求相关的操作
- 命令接口Command:命令是一个接口,用于封装请求的若干个方法
- 具体命令ConcreteCommand:实现接口类的实例
- 请求者Invoker:负责调用具体命令
package com.rfos.design.demo;
/**
* 命令模式
* <p>
* 命令模式的目的就是达到命令的发出者和执行者之间解耦,实现请求和执行分开。
* </p>
*/
public class CommandDemo {
/**
* 命令接口
*/
interface Command{
void exe();
}
/**
* 命令发出者
*/
static class Invoker{
private Command mCommand;
public Invoker(Command command) {
mCommand = command;
}
public void action() {
mCommand.exe();
}
}
/**
* 命令执行者
*/
static class Receiver{
public void action() {
System.out.println("command start");
}
}
/**
* 命令实现类
*/
static class CommandImpl implements Command{
private Receiver mReceiver;
public CommandImpl(Receiver receiver) {
mReceiver = receiver;
}
@Override
public void exe() {
mReceiver.action();
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
Invoker invoker = new Invoker(new CommandImpl(new Receiver()));
invoker.action();
}
}
interface Expression{
int interpret(Context context);
}
/**
* 加法解释器
*/
static class Plus implements Expression{
@Override
public int interpret(Context context) {
return context.getNum1() + context.getNum2();
}
}
/**
* 减法解释器
*/
static class Minus implements Expression{
@Override
public int interpret(Context context) {
return context.getNum1() - context.getNum2();
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
//998-668+1080
int interpret = new Plus().interpret(new Context(new Minus().interpret(new Context(998, 668)), 1080));
System.out.println(interpret);
}
}
23 命令模式
将一个请求封装为一个对象,从而使用户可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。
结构
主要包含四个角色
- 接收者Receiver:接收者是一个类的实例,负责执行与请求相关的操作
- 命令接口Command:命令是一个接口,用于封装请求的若干个方法
- 具体命令ConcreteCommand:实现接口类的实例
- 请求者Invoker:负责调用具体命令
package com.rfos.design.demo;
/**
* 命令模式
* <p>
* 命令模式的目的就是达到命令的发出者和执行者之间解耦,实现请求和执行分开。
* </p>
*/
public class CommandDemo {
/**
* 命令接口
*/
interface Command{
void exe();
}
/**
* 命令发出者
*/
static class Invoker{
private Command mCommand;
public Invoker(Command command) {
mCommand = command;
}
public void action() {
mCommand.exe();
}
}
/**
* 命令执行者
*/
static class Receiver{
public void action() {
System.out.println("command start");
}
}
/**
* 命令实现类
*/
static class CommandImpl implements Command{
private Receiver mReceiver;
public CommandImpl(Receiver receiver) {
mReceiver = receiver;
}
@Override
public void exe() {
mReceiver.action();
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
Invoker invoker = new Invoker(new CommandImpl(new Receiver()));
invoker.action();
}
}