前言

设计模式这个老生常谈的东西,在以往的面试题以及面试中会经常问到,关于设计模式,网上有很多文章对其进行阐述。

但是看了那么多设计模式你真的懂了吗?

在项目中除了单例模式,你还用到了哪些设计模式呢?

各个设计模式又有什么利弊呢?如何去正确的考量呢?

在这里,我只是通过自己的理解,把我所知道的写出来, 文章很长,建议先收藏起来,慢慢看(ps:_(:з」∠)_轻喷)。

—、设计模式的分类

总的来说,设计模式分为三种:创建模式、结构模式、行为模式

1. 创建模式

创建模式:提供实例化的方法,为适合的状况提供相应的对象创建方法。 其中属于创建模式的是:单例模式、建造者模式、工厂方法模式、抽象工厂模式、原型模式。

1. 单例模式(Singleton Pattern)

定义:确保一个类中有且只有一个实例,而且自行实例化。 这里可以去看我之前写的如何写出一个好的单例模式

2. 建造者模式 (Builder Pattern)

定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 更多内容请看 浅析 builder 模式

3. 工厂方法模式(Factory Method Pattern)

定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。 下面引入一个简单工厂模式: 肉制品加工厂加工不同的肉制品。

//定一个抽象方法用来生产肉制品
abstract class Product {
	public abstract void method();
}
class MuttonProduct extends Product {
	@Override
	public void mothod() {
		System.out.println("生产出来了羊肉....");
	}
}
class PorkProduct extends Product {
	@Override
	public void mothod() {
		System.out.println("生产出来了猪肉....");
	}
}
abstract class Creator {
	public abstract <T extends Product> T createProduce(Class<T> product);
}

class OneCreator extends Creator{
/**
* 传入的参数,是 Product 类的子类。
*/
@Override
public <T extends Product> T createProduce(Class<T> product) {
Product p = null;
try {
//Class 类创建一个 工厂类实例
p = (Product) Class.forName(product.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) p;
}
}

public class Test {
public static void main(String[] args) {
// 通过创建子类对象,将接口实例化。
Creator cFactory = new OneCreator();
// 通过子类的方法,创建一个需要的对象。
ForkProduct food = cFactory.createProduce(ForkProduct.class);
food.mothod();
}
}

复制代码

Product, 抽象类,表示不同的肉制品。

PorkProduct, 实现类,继承 Product。

MuttonProduct,同上。

Creator 抽象工厂类,提供加工方法。

OneCreator 实现类,加工不同的肉制品。

工厂模式的优点:

  1. 代码机构清晰,有很好的封装性。降低了模块间的耦合性。
  2. 有很好的扩展性。
  3. 屏蔽产品类,产品类对外提供的是一个接口,只要接口不改变系统中的上层模块就不会发生改变。

##### 扩展

1. 替代单例
class SingtonFactory {
	private static Singleton single;
	static {
		try {
			Class c = Class.forName(Singleton.class.getName());
			//获取无参构造
			Constructor<Singleton> constractor = c.getDeclaredConstructor();
			//设置无参构造是可访问的
			constractor.setAccessible(true);
			//产生一个实例对象
			single = constractor.newInstance();
		} catch (Exception e) {
			System.out.println("创建失败。。。")
		}
	}
	public Singleton getSingle() {
		return single;
	}
}

class Singleton {
// 构造私有化
private Singleton {
}
public void method () {
System.out.println(“sington。。。。”)
}
}

复制代码
2. 延迟初始化

一个对象被使用完毕,并不立刻释放,保持其初始状态,等待再次被使用

interface Product {
	void method();
}
class MuttonProduct implements Product {
	@Override
	public void mothod() {
		System.out.println("生产出来了羊肉....");
	}
}
class PorkProduct implements Product {
	@Override
	public void mothod() {
		System.out.println("生产出来了猪肉....");
	}
}
abstract class Creator {
	public abstract <T extends Product> T createProduce(String type);
}

class OneCreator extends Creator{
private static Map<String,Product> map = new HashMap<String,Product>();
@Override
public <T extends Product> T createProduce(String type) {
Product p = null;
if(map.containsKey(type)) {
p = map.get(type);
} else {
if(type.equals(“pork”)) {
p = new PorkProduct();
} else {
p = new MuttonProduct();
}
}
map.put(type, p);
return p;
}
}

public class Test {
public static void main(String[] args) {
for(int i=0;i<5;i++){
Product p = new OneCreator().createProduce(“pork”);
p.mothod();
System.out.println(“——————————”);
}
}
}

复制代码
4. 抽象工厂模式 (Abstract Factory)

定义:为创建一组相关或相互依赖的对象提供一个接口,而且无须指定他们的具体类。

抽象工厂模式是工厂模式的升级版,针对的是多业务类型。

通用模式:

public class MyClass {
    public static void main(String [] args) {
        IProduct p1 = new Creator1();
        ProductA1 a1 = (ProductA1) p1.createA();
        a1.method();
        IProduct p2 = new Creator();
        ProductB1 b1 = (ProductB1) p2.createB();
        b1.method();
    }
}

abstract class AbstractProductA {
public void shareMethod (){
System.out.println(“生产产品共同的方法”);
}
abstract void method();
}
abstract class AbstractProductB {
public void shareMethod () {
System.out.println(“生产产品共同的方法”);
}
abstract void method();
}
interface IProduct {
AbstractProductA createA();
AbstractProductB createB();
}
class ProductA1 extends AbstractProductA {

@Override
void <span class="hljs-function"><span class="hljs-title">method</span></span>() {
    System.out.println(<span class="hljs-string">"生产A1"</span>);
}

}
class ProductA2 extends AbstractProductA {

@Override
void <span class="hljs-function"><span class="hljs-title">method</span></span>() {
    System.out.println(<span class="hljs-string">"生产A2"</span>);
}

}
class ProductB1 extends AbstractProductB{

@Override
void <span class="hljs-function"><span class="hljs-title">method</span></span>() {
    System.out.println(<span class="hljs-string">"生产B1"</span>);
}

}
class ProductB2 extends AbstractProductB {

@Override
void <span class="hljs-function"><span class="hljs-title">method</span></span>() {
    System.out.println(<span class="hljs-string">"生产B2"</span>);
}

}

class Creator1 implements IProduct{

@Override
public AbstractProductA <span class="hljs-function"><span class="hljs-title">createA</span></span>() {
    <span class="hljs-built_in">return</span> new ProductA1();
}

@Override
public AbstractProductB <span class="hljs-function"><span class="hljs-title">createB</span></span>() {
    <span class="hljs-built_in">return</span> new ProductB2();
}

}
class Creator implements IProduct {

@Override
public AbstractProductA <span class="hljs-function"><span class="hljs-title">createA</span></span>() {
    <span class="hljs-built_in">return</span> new ProductA2();
}

@Override
public AbstractProductB <span class="hljs-function"><span class="hljs-title">createB</span></span>() {
    <span class="hljs-built_in">return</span> new ProductB1();
}

}

复制代码

抽象工厂模式 一般是 一个接口,多个抽象类,n 个实现类,从上面的代码可以看出它除了有工厂方法模式的优点外,还可以在类的内部对产品族进行约束。所谓产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。

抽象工厂模式的缺点也是显而易见的,就是产品族的扩展比较困难。

5. 原型模式

定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

java 提供了一个 Cloneable 接口,来标示这个类是可拷贝的,通过该接口中的 clone 方法对对象进行拷贝。

例子:某电商平台双十一搞活动,需要群发邮件通知。

class MyClass {
    public static void main(String [] args) {
        Mail mail = new Mail(new Template());
        for (int i = 0 ;i < 100; i++) {
            try {
                Mail cMail = (Mail) mail.clone();
                cMail.setReceiver(getReceiver(6) + ".com");
                sendMail(cMail);
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
    }
private static void sendMail(Mail cMail) {
    System.out.println(<span class="hljs-string">"收件人"</span> + cMail.getReceiver() + <span class="hljs-string">"发送成功"</span>);
}

private static String getReceiver(int i) {
    String s = <span class="hljs-string">"abcdefghijklmnopqrstuvwxz"</span>;
    Random random = new Random();
    StringBuffer sb = new StringBuffer();
    <span class="hljs-keyword">for</span> (int j =0 ;j &lt;= i; j++) {
        sb.append(s.charAt(random.nextInt(s.length())));
    }
    <span class="hljs-built_in">return</span> sb.toString();
}

}

class Template {
private String subject = “双十一优惠活动”;
private String context = “双十一优惠活动,全场满 99 减 5 元”;

public String <span class="hljs-function"><span class="hljs-title">getSubject</span></span>() {
    <span class="hljs-built_in">return</span> subject;
}

public void <span class="hljs-built_in">set</span>Subject(String subject) {
    this.subject = subject;
}

public String <span class="hljs-function"><span class="hljs-title">getContext</span></span>() {
    <span class="hljs-built_in">return</span> context;
}

public void <span class="hljs-built_in">set</span>Context(String context) {
    this.context = context;
}

}
class Mail implements Cloneable {
// 收件人
private String receiver;
// 标题
private String subject;
// 内容
private String context;

public Mail(Template template) {
    this.subject = template.getSubject();
    this.context = template.getContext();
}

public String <span class="hljs-function"><span class="hljs-title">getReceiver</span></span>() {
    <span class="hljs-built_in">return</span> receiver;
}

public void <span class="hljs-built_in">set</span>Receiver(String receiver) {
    this.receiver = receiver;
}

public String <span class="hljs-function"><span class="hljs-title">getSubject</span></span>() {
    <span class="hljs-built_in">return</span> subject;
}

public void <span class="hljs-built_in">set</span>Subject(String subject) {
    this.subject = subject;
}

public String <span class="hljs-function"><span class="hljs-title">getContext</span></span>() {
    <span class="hljs-built_in">return</span> context;
}

public void <span class="hljs-built_in">set</span>Context(String context) {
    this.context = context;
}
// 重写 <span class="hljs-built_in">clone</span>
@Override
protected Object <span class="hljs-built_in">clone</span>() throws CloneNotSupportedException {
    Mail mail = (Mail) super.clone();
    <span class="hljs-built_in">return</span> mail;
}

}

复制代码

原型模式是内存二进制流的法拷贝,比 new 一个新的对象好的多。

原型模式是从内存中拷贝,构造函数是不会执行的。拷贝分为浅拷贝和深拷贝,浅拷贝只是拷贝对象,其对象内部的数组、引用对象都不会拷贝。

原型模式需要注意的是:出现 final 的对象或变量,不能 clone

深拷贝的例子:

public class Prototype {
	public static void main(String[] args) {
			//创建一个对象
			MyClone myClone = new MyClone();
			myClone.setArrayList("abs");
			//将该对象clone。
			MyClone clone2 = (MyClone) myClone.clone();
			clone2.setArrayList("gh");
			//输出原对象的结果。
			System.out.println("原对象...."+myClone.getArrayList());
			//输出拷贝后的结果。
			System.out.println("拷贝结果...."+clone2.getArrayList());
	}
}
class MyClone implements Cloneable{
	private ArrayList<String> arrayList = new ArrayList<String>();
	@SuppressWarnings("unchecked")
	@Override
	public MyClone clone(){
		MyClone myClone =null;
		try {
			myClone = (MyClone) super.clone();
			//把私有对象也进行拷贝。做到深拷贝的效果
			myClone.arrayList = (ArrayList<String>) this.arrayList.clone();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return myClone;
	}
	public ArrayList<String> getArrayList() {
		return arrayList;
	}
	public void setArrayList(String name) {
		this.arrayList.add(name);
	}

}

复制代码

输出结果:

原对象....[abs]
拷贝结果....[abs, gh]
复制代码

2. 结构模式

结构模式:通常用来处理实体之间的关系,使得这些实体能够更好地协同工作。

其中属于结构模式的是:装饰模式、适配器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

1. 代理模式(Proxy Pattern)

定义: 为其他对象提供一种代理以控制对这个对象的访问。

例子:明星拍广告,要和经纪人沟通。

public class MyClass {
    public static void main(String [] args) {
        Agent mAgent = new Agent(new Star());
        mAgent.shootAdvertisement();
    }
}

interface Subject {
public void shootAdvertisement();
}

class Star implements Subject {
@Override
public void shootAdvertisement() {
System.out.println(“拍广告。。。”);
}
}

class Agent implements Subject {
// 经纪人 ,代理类
private Subject star = null;
// 设置被代理类
public Agent(Subject star) {
this.star = star;
}

@Override
public void <span class="hljs-function"><span class="hljs-title">shootAdvertisement</span></span>() {
    before();
    star.shootAdvertisement();
    after();
}

private void <span class="hljs-function"><span class="hljs-title">after</span></span>() {
    System.out.println(<span class="hljs-string">"处理拍广告之前的各项工作"</span>);
}

private void <span class="hljs-function"><span class="hljs-title">before</span></span>() {
    System.out.println(<span class="hljs-string">"处理拍广告之后的善后工作"</span>);
}

}

复制代码

代理模式分为:

  • 静态代理模式

    • 普通代理模式
    • 强制带离模式
  • 动态代理模式

普通代理模式:要求客户端只能访问代理角色,而不能访问真实角色。

例子:游戏代练

public class MyClass {
    public static void main(String [] args) {
        GameProxy gameProxy = new GameProxy("Miss");
        gameProxy.login();
        gameProxy.upgrade();
    }
}

interface IGamePlayer {
public void login();
public void upgrade();
}

class GamePlayer implements IGamePlayer {
public String name = "";

public GamePlayer(IGamePlayer gamePlayer, String name) {
    <span class="hljs-keyword">if</span> (gamePlayer == null) {
        try {
            throw new Exception(<span class="hljs-string">"不能创建对象"</span>);
        } catch (Exception e) {
            e.printStackTrace();
        }
    } <span class="hljs-keyword">else</span> {
        this.name = name;
    }
}

@Override
public void <span class="hljs-function"><span class="hljs-title">login</span></span>() {
    System.out.println(this.name + <span class="hljs-string">"-登录成功"</span>);
}

@Override
public void <span class="hljs-function"><span class="hljs-title">upgrade</span></span>() {
    System.out.println(<span class="hljs-string">"升级了!!!!"</span>);
}

}

class GameProxy implements IGamePlayer {
private GamePlayer mGamePlayer = null;

public GameProxy(String name) {
    this.mGamePlayer = new GamePlayer(this, name);

}

@Override
public void <span class="hljs-function"><span class="hljs-title">login</span></span>() {
    mGamePlayer.login();
}

@Override
public void <span class="hljs-function"><span class="hljs-title">upgrade</span></span>() {
    mGamePlayer.upgrade();
}

}

复制代码
强制代理

必须通过真实角色找到代理角色,否则无法访问

public class MyClass {
    public static void main(String [] args) {
        GamePlayer player = new GamePlayer("Miss");
        player.login();
        player.upgrade();
        GameProxy proxy = new GameProxy(player.getPlayer());
        proxy.login();
        proxy.upgrade();
    }
}

interface IGamePlayer {
public void login();
public void upgrade();
IGamePlayer getPlayer();
}

class GamePlayer implements IGamePlayer {
private IGamePlayer player;
private String name;
public GamePlayer(String name) {
this.name = name;
}

private boolean <span class="hljs-function"><span class="hljs-title">isProxy</span></span>() {
    <span class="hljs-keyword">if</span> (this.player == null) {
        <span class="hljs-built_in">return</span> <span class="hljs-literal">false</span>;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">return</span> <span class="hljs-literal">true</span>;
    }
}

@Override
public void <span class="hljs-function"><span class="hljs-title">login</span></span>() {
    <span class="hljs-keyword">if</span> (this.isProxy()) {
        System.out.println(this.name + <span class="hljs-string">"-登录成功"</span>);
    } <span class="hljs-keyword">else</span> {
        System.out.println(<span class="hljs-string">"请使用代理访问"</span>);
    }
}

@Override
public void <span class="hljs-function"><span class="hljs-title">upgrade</span></span>() {
    <span class="hljs-keyword">if</span> (this.isProxy()) {
        System.out.println(<span class="hljs-string">"升级了!!!!"</span>);
    } <span class="hljs-keyword">else</span> {
        System.out.println(<span class="hljs-string">"请使用代理访问"</span>);
    }
}

@Override
public IGamePlayer <span class="hljs-function"><span class="hljs-title">getPlayer</span></span>() {
    this.player = new GameProxy(this);
    <span class="hljs-built_in">return</span> this.player;
}

}

class GameProxy implements IGamePlayer {
private IGamePlayer gamePlayer;

public GameProxy(IGamePlayer gamePlayer) {
    this.gamePlayer = gamePlayer;
}

@Override
public void <span class="hljs-function"><span class="hljs-title">login</span></span>() {
    this.gamePlayer.login();
}

@Override
public void <span class="hljs-function"><span class="hljs-title">upgrade</span></span>() {
    this.gamePlayer.upgrade();
}

@Override
public IGamePlayer <span class="hljs-function"><span class="hljs-title">getPlayer</span></span>() {
    <span class="hljs-built_in">return</span> this;
}

}

复制代码

输出结果:

请使用代理访问
请使用代理访问
Miss-登录成功
升级了!!!!
复制代码
动态代理

动态代理:实现阶段不用关系代理是哪个,而在运行阶段指定具体哪个代理。

public class MyClass {
    public static void main(String [] args) {
        IGamePlayer mGamePlayer = new GamePlayer("Miss");
        InvocationHandler handler = new GameProxy(mGamePlayer);
        //生成一个代理者
        // ClassLoader: 指定当前目标对象使用类加载器
        // Class<?> [] interface: 目标对象实现接口的类型
        // InvocationHandler: 事件处理,执行目标对象的方法时,会触发事件处理器的方法。
        IGamePlayer player = (IGamePlayer) Proxy.newProxyInstance(mGamePlayer.getClass().getClassLoader(), new Class[]{IGamePlayer.class}, handler);
        player.login("Miss", "123456a");
        player.upgrade();
    }
}

interface IGamePlayer {
public void login(String name, String password);
public void upgrade();
}

class GamePlayer implements IGamePlayer {
private String name = "";

public GamePlayer(String name) {
    this.name = name;
}

@Override
public void login(String name, String password) {
    System.out.println(name + <span class="hljs-string">"登录成功"</span>);
}

@Override
public void <span class="hljs-function"><span class="hljs-title">upgrade</span></span>() {
    System.out.println(this.name + <span class="hljs-string">"升级了"</span>);
}

}

class GameProxy implements InvocationHandler {
// 被代理的对象
private Object obj;
// 将需要代理的实例通过构造方法传递给代理
public GameProxy(Object obj) {
this.obj = obj;
}

@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
    <span class="hljs-keyword">if</span> (method.getName().equalsIgnoreCase(<span class="hljs-string">"login"</span>)) {
    // 在这个方法不收影响的情况下,在方法的前后添加新的功能
    // 从侧面切入从而达到扩展的效果的编程,就是面向切面编程(AOP Aspect Oriented Programming)				
        System.out.println(<span class="hljs-string">"代理登录了"</span>);
        Object result = method.invoke(this.obj, objects);
        <span class="hljs-built_in">return</span>  result;
    }
    Object result = method.invoke(this.obj, objects);
    <span class="hljs-built_in">return</span>  result;
}

}

复制代码

动态代理模式的一般模式:

public class MyClass {
    public static void main(String [] args) {
        Subject subject = new MySubject();
        InvocationHandler handler = new MyInvocationHandler(subject);
        ClassLoader loader = subject.getClass().getClassLoader();
        Class <?>[] in = subject.getClass().getInterfaces();
        Subject s = DynamicProxy.newProxyInstance(loader, in, handler);
        s.doSomething();
    }
}

interface Subject {
void doSomething();
}
class MySubject implements Subject {
@Override
public void doSomething() {
System.out.println(“吃饭睡觉打豆豆”);
}
}
interface Advice {
public void exec();
}
class BeforeAdvice implements Advice {
@Override
public void exec() {
System.out.println(“前置方法”);
}
}
class AfterAdvice implements Advice {
@Override
public void exec() {
System.out.println(“后置方法”);
}
}
class MyInvocationHandler implements InvocationHandler {
private Subject mySubject;

public MyInvocationHandler(Subject mySubject) {
    this.mySubject = mySubject;
}

@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
    Advice beforeAdvice = new BeforeAdvice();
    beforeAdvice.exec();
    Object result = method.invoke(this.mySubject, objects);
    Advice afterAdvice = new AfterAdvice();
    afterAdvice.exec();
    <span class="hljs-built_in">return</span> result;
}

}
class DynamicProxy {
public static <T> T newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler){
@SuppressWarnings(“unchecked”)
T t = (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
return t;
}
}

复制代码
2. 装饰模式(Decorator Pattern)

定义:动态的给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更佳灵活

模式中的角色
  • 抽象构建(Component):定义个个抽象接口,用于给对象动态的添加职责。
  • 具体构建(ConcreteComponent):定义一个具体的对象,也可以给这个对象添加一些职责。
  • 装饰类(Decorator):装饰抽象类。继承了 Component,从外类来扩展 Component 类的功能。
  • 具体装饰类:(ConcretorDecorator):负责给构建对象添加职责。

模式的一般模式:

public class MyClass {
    public static void main(String [] args) {
        Component component = new ConcreteComponent();
        ConcreteDecorator decorator = new ConcreteDecorator(component);
        decorator.doSomething();
    }
}

abstract class Component {
public abstract void doSomething();
}
class ConcreteComponent extends Component {

@Override
public void <span class="hljs-function"><span class="hljs-title">doSomething</span></span>() {
    System.out.println(<span class="hljs-string">"具体实现的方法"</span>);
}

}
abstract class Decorator extends Component {
private Component component;

public Decorator(Component component) {
    this.component = component;
}

@Override
public void <span class="hljs-function"><span class="hljs-title">doSomething</span></span>() {
    this.component.doSomething();
}

}
class ConcreteDecorator extends Decorator {

public ConcreteDecorator(Component component) {
    super(component);
}

@Override
public void <span class="hljs-function"><span class="hljs-title">doSomething</span></span>() {
    System.out.println(<span class="hljs-string">"方法前要执行的动作"</span>);
    super.doSomething();
    System.out.println(<span class="hljs-string">"方法后要执行的动作"</span>);
}

}

复制代码
装饰模式的优点
  • 装饰类和被装饰类可以独立的发展,不会相互耦合。
  • 装饰模式是继承关系的一种替代方案,Decorator 不管修饰多少层,返回的对象还是 Component,实现的还是 is-a 的关系。
  • 装饰模式可以动态的扩展一个实现类的功能。
装饰模式的缺点
  • 多层的装饰模式是比较复杂的。
装饰模式的使用场景
  • 扩展一个类的功能,或给一个类增加附加的功能。
  • 动态的给一个对象增加功能,这些功能可以动态的撤销。
  • 为一些类进行改装或者增肌功能,首选装饰模式。
3. 适配器模式

定义:将一个类的接口编程客户端所期待的另一个接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

适配器模式的一般模式:

public class MyClass {
    public static void main(String [] args) {
        Target target = new ConcreteTarget();
        target.doSomething();
        Target adapter = new Adapter();
        adapter.doSomething();
    }
}

interface Target {
void doSomething();
}
class ConcreteTarget implements Target {

@Override
public void <span class="hljs-function"><span class="hljs-title">doSomething</span></span>() {
    System.out.println(<span class="hljs-string">"我是目标角色,现在要使用我的..."</span>);
}

}
abstract class Adaptee {
public void doSome () {
System.out.println(“我是源角色,从这里转变。。。”);
}
}
class Adapter extends Adaptee implements Target {

@Override
public void <span class="hljs-function"><span class="hljs-title">doSomething</span></span>() {
    super.doSome();
}

}

复制代码

适配器模式在 android 中比较常见,比如 ListView 的适配器。 例子:有两种插座:两孔的和三孔的。在一个宾馆里 只有两孔的插座,所有我们要做一些操作,让我们可以用三孔的插座

public class MyClass {
    public static void main(String [] args) {
        TSocketInterface socket = new ThreeSocket();
        Hotel hotel = new Hotel();
        SocketAdapter adapter = new SocketAdapter(socket);
        hotel.setSocket(adapter);
        hotel.charge();
    }
}

interface SocketInterface {
void TwoRound();
}

class TwoSocket implements SocketInterface {

@Override
public void <span class="hljs-function"><span class="hljs-title">TwoRound</span></span>() {
    System.out.println(<span class="hljs-string">"使用两孔插座"</span>);
}

}
interface TSocketInterface {
void ThreeRound();
}
class ThreeSocket implements TSocketInterface {

@Override
public void <span class="hljs-function"><span class="hljs-title">ThreeRound</span></span>() {
    System.out.println(<span class="hljs-string">"使用三孔插座"</span>);
}

}
class SocketAdapter implements SocketInterface {
private TSocketInterface socket;

public SocketAdapter(TSocketInterface socket) {
    this.socket = socket;
}

@Override
public void <span class="hljs-function"><span class="hljs-title">TwoRound</span></span>() {
    this.socket.ThreeRound();
}

}
class Hotel {
private SocketInterface socket;

public void <span class="hljs-built_in">set</span>Socket(SocketInterface socket) {
    this.socket = socket;
}
public void <span class="hljs-function"><span class="hljs-title">charge</span></span> () {
    socket.TwoRound();
}

}

复制代码
适配器模式的特点
  • 适配器对象实现原有接口
  • 适配器对象组合一个实现新接口的对象
  • 对适配器原有接口方法的调用被委托给新接口的实例的特定方法。
4. 外观模式

定义: 要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。

例子:进门分为几个步骤:拿钥匙、开门、进房间。而关门的话,也需要差不多的步骤,这时就需要一个外观模式,通过一个合理的方式将这些动作包装起来。

public class MyClass {
    public static void main(String [] args) {
        Facade facade = new Facade(new Key(), new Door(), new House());
        facade.in();
        facade.out();
    }
}

class Key {
public void takekey () {
System.out.println(“拿钥匙”);
}
}
class Door {
public void openDoor () {
System.out.println(“开门”);
}
public void closeDoor () {
System.out.println(“关门”);
}
}
class House {
public void goIn () {
System.out.println(“进入房间”);
}
public void goOut () {
System.out.println(“出房间”);
}
}
class Facade {
private Key key;
private Door door;
private House house;

public Facade(Key key, Door door, House house) {
    this.key = key;
    this.door = door;
    this.house = house;
}
public void <span class="hljs-function"><span class="hljs-title">in</span></span> () {
    key.takekey();
    door.openDoor();
    house.goIn();
}
public void <span class="hljs-function"><span class="hljs-title">out</span></span> () {
    key.takekey();
    house.goOut();
    door.closeDoor();
}

}

复制代码
外观模式的优点
  • 减少系统的相互依赖
  • 提高灵活性
  • 提高安全性
外观模式的缺点
  • 不符合开闭原则
使用场景
  • 为一个复杂的模块后子系统提供一个供外界访问的接口
  • 子系统相互独立,外界对子系统的访问只要黑箱操作就可以
  • 预防低水平人员带来的风险扩散
5. 组合模式(Composite Pattern)

定义:将对象组合成树形结构表示“部分 - 整体”的层次结构。Composite 模式使得用户对单个对象和组合对象的使用具有一致性。

组成
  • 抽象构件(Component): 定义参与组合对象的共有方法和属性,可以定义一些默认行为或属性。
  • 树叶构件(Leaf):组合中叶子对象,其下没有其他分支,是最小的单位。
  • 树枝构件(Composite):在组合中表示分直接点对象,有子节点,存储子部件。

一般模式:

public class MyClass {
    public static void main(String [] args) {
        /**
         *           composite1
         *           /      \
         *        leaf1   composite2
         *                  /   \
         *               leaf2  leaf3
         *
         * */
        Component leaf1=new Leaf();
        Component leaf2=new Leaf();
        Component leaf3=new Leaf();
        Composite composite1=new Composite();
        Composite composite2=new Composite();
    composite2.add(leaf2);
    composite2.add(leaf3);
    composite1.add(leaf1);
    composite1.add(composite2);

    composite1.doSomething();
}

}

interface Component {
public void doSomething();
}

class Leaf implements Component {

@Override
public void <span class="hljs-function"><span class="hljs-title">doSomething</span></span>() {
    System.out.println(<span class="hljs-string">"Leaf doSomething"</span>);
}

}
class Composite implements Component {
List<Component> childs = new ArrayList<>();
public void add (Component child) {
this.childs.add(child);
}
public void remove(Component component) {
this.childs.remove(component);
}
public Component getChild(int i) {
return this.childs.get(i);
}
@Override
public void doSomething() {
for (Component child : childs) {
child.doSomething();
}
}
}

复制代码
实现方式
  • 透明式的组合模式:将管理子构件的方法定义在 Component 接口中,这样 Leaf 类就需要处理这些对其意义不大的方法,在接口层次上 Leaf 和 Composite 没有区别,这就是透明性。
  • 安全式的组合模式:将管理子构件的方法定义在 Composite 中,这样编译时任何从 Leaf 中增加或删除对象的尝试都将会被发现。
适用场景
  • 忽略组合对象和单个对象的不同,用户将统一地使用组合结构中所有对象。
  • 想表示对象的部分 - 整体层次结构。
6. 桥接模式

定义: 将抽象和实现解耦,使得两者之间可以独立的变化

桥接的用意是将抽象化和结构化解耦,使得二者可以独立变化,就像 JDBC 桥 DriverManage 一样,JDBC 进行连接数据库的时候,在各个数据库之间进行切换,基本不用改动太多代码,因为 JDBC 提供统一接口,每个数据库提供各自的实现,用一个叫做数据库驱动的程序来桥接就行。

一般模式:

public class MyClass {
    public static void main(String [] args) {
        Sourceable sourceable = new ConcreteSource1();
        Bridge bridge = new MyBridge(sourceable);
        bridge.method();
    }
}

interface Sourceable {
public void doSomething();
public void doAnything();
}
class ConcreteSource1 implements Sourceable {
@Override
public void doSomething() {
System.out.println(“this is first source doSomething”);
}

@Override
public void <span class="hljs-function"><span class="hljs-title">doAnything</span></span>() {
    System.out.println(<span class="hljs-string">"this is first source doAnything"</span>);
}

}
class ConcreteSource2 implements Sourceable {

@Override
public void <span class="hljs-function"><span class="hljs-title">doSomething</span></span>() {
    System.out.println(<span class="hljs-string">"this is second doSomething"</span>);
}

@Override
public void <span class="hljs-function"><span class="hljs-title">doAnything</span></span>() {
    System.out.println(<span class="hljs-string">"this is second doAnything"</span>);
}

}

abstract class Bridge {
private Sourceable sourceable;

public Bridge(Sourceable sourceable) {
    this.sourceable = sourceable;
}

public Sourceable <span class="hljs-function"><span class="hljs-title">getSourceable</span></span>() {
    <span class="hljs-built_in">return</span> sourceable;
}
public void <span class="hljs-function"><span class="hljs-title">method</span></span> () {
    sourceable.doSomething();
}

}
class MyBridge extends Bridge {

public MyBridge(Sourceable sourceable) {
    super(sourceable);
}

@Override
public void <span class="hljs-function"><span class="hljs-title">method</span></span>() {
    super.getSourceable().doAnything();
}

}

复制代码
桥接模式的优点:
  • 抽象和实现分离
  • 优秀的扩充能力
  • 实现细节对客户透明
桥接模式的使用场景
  • 不希望或不适用使用继承的场景
  • 接口或抽象不稳定的场景
  • 重用性要求比较高的场景
7. 享元模式

定义:使用共享对象可有效的支持大量的细粒度的对象。

细粒度对象由于对象数量多且性质相近,我们将其分为两个部分:内部状态和外部状态。

  • 内部状态:内部状态是对象可共享出来的信息,存储在享元对象内部并且不会随环境而改变。如 id,adress 等。
  • 外部状态:对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。

一般模式:

  • Flyweight: 抽象享元角色,定义出对象的外部状态和北部状态的接口或接口实现。
  • ConcreteFlyweight 具体的享元角色,实现抽象角色定义的的义务。
  • FlyweightFactory: 构造一个对象池,从池中提供对象。
public class MyClass {
    public static void main(String [] args) {
        FlyweightFactory.getFlyweight("Miss");
        FlyweightFactory.getFlyweight("Boss");
        FlyweightFactory.getFlyweight("Miss");
    }
}
abstract class Flyweight {
    //内部状态
   private String intrinsic;
    // 外部状态
    private String extrinsic;
    // 构造方法提供外部字符串
    public Flyweight(String extrinsic) {
        this.extrinsic = extrinsic;
    }
public void <span class="hljs-built_in">set</span>Intrinsic(String intrinsic) {
    this.intrinsic = intrinsic;
}

public String <span class="hljs-function"><span class="hljs-title">getIntrinsic</span></span>() {
    <span class="hljs-built_in">return</span> intrinsic;
}
public abstract void operate ();

}

class ConcreteFlyweight extends Flyweight {
public ConcreteFlyweight(String extrinsic) {
super(extrinsic);
}

@Override
public void <span class="hljs-function"><span class="hljs-title">operate</span></span>() {
    System.out.println(<span class="hljs-string">"this is first operate  "</span>);
}

}
class ContreteFlyweight2 extends Flyweight {

public ContreteFlyweight2(String extrinsic) {
    super(extrinsic);
}

@Override
public void <span class="hljs-function"><span class="hljs-title">operate</span></span>() {
    System.out.println(<span class="hljs-string">"this is second operate"</span>);
}

}
// 享元工厂
class FlyweightFactory {
private static Map<String, Flyweight> list = new HashMap<>();
public static Flyweight getFlyweight (String extrinsic) {
Flyweight flyweight = null;
if (list.containsKey(extrinsic)) {
System.out.println(“从对象池中取对象。。”);
flyweight = list.get(extrinsic);
} else {
flyweight = new ConcreteFlyweight(extrinsic);
list.put(extrinsic, flyweight);
System.out.println(“创建新对象。。”);
}
return flyweight;
}
}

复制代码
享元模式优点:

减少应用创建的对象,降低使用内存,增强程序性能。

适用场景

系统中存在很多相似对象,细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关。

3. 行为模式

行为模式:用于在不同的实体之间进行通信,为实体之间的通信提供更容易,更灵活的通信方法。

其中属于行为模式的是:观察者模式、策略模式、访问者模式、中介者模式、状态模式、备忘录模式、责任链模式、模版方法模式、迭代子模式、命令模式、解释器模式。

1. 观察者模式

定义:定义对象间一种一对多的依赖关系,使得每当一个对象发生变化,其他依赖它的对象都会得到通知并自动更新。

观察者模式又叫发布 - 订阅模式,在 Android 中用的还是比较多的,推荐理解掌握。

一般模式
public class MyClass {
    public static void main(String [] args) {
        // 创建被观察者
        Subject subject = new ConcreteSubject();
        // 添加观察者
        subject.add(new ConcreteObserver("徐晓路"));
        subject.add(new ConcreteObserver("小埋"));
        // 更新信息
        subject.notify("博客系统更新了");
}

}
// 观察者接口
interface Observer {
public void update(String message);
}
// 具体观察者
class ConcreteObserver implements Observer {
private String name = "";

public ConcreteObserver(String name) {
    this.name = name;
}

@Override
public void update(String message) {
    System.out.println(this.name +<span class="hljs-string">"-"</span>+ message);
}

}

// 抽象被观察者
interface Subject {
/*
* 增加观察者
* /
void add(Observer ob);
/

* 删除观察者
* /
void remove(Observer ob);
/

* 更新信息
* */
void notify(String message);
}
class ConcreteSubject implements Subject {
private List<Observer> list = new ArrayList<>();
@Override
public void add(Observer ob) {
list.add(ob);
}

@Override
public void remove(Observer ob) {
    list.remove(ob);
}

@Override
public void notify(String message) {
    <span class="hljs-keyword">for</span> (Observer observer : list) {
        observer.update(message);
    }
}

}

复制代码
  • Observer:抽象观察者,提供一个接口,在得到通知时更新自己。
  • ConcreteObserver: 具体观察者,实现抽象观察者,在得到通知时更新自己的状态
  • Subject: 抽象被观察者,将所有的观察者存储在一个集合里,并提供增加、删除观察者的接口
  • ConcreteSubject: 具体被观察者,实现抽象被观察者接口,得以在更新时通知所有观察者。
观察者模式的优点
  • 观察者和被观察者之间是抽象耦合,变换互不影响
  • 一套触发机制
观察者模式的缺点
  • 观察者模式是,一个被观察者,多个观察者,一旦 一个观察者卡顿,就会硬系哦昂其他观察者,
适用场景
  • 关联行为场景,关联行为是可查分的,而不是“组合”关系
  • 事件多出发场景
  • 跨系统的消息交换,如 消息队列

观察者模式在 Android 源码中使用还是蛮多的,比如OnClickListenerContentObserverandroid.database.Observable, 第三方组件像RxJavaRxAndroidEventBus都用到了观察者模式,这里就不过多分析了。

2. 策略模式

定义:定义一组算法,把每一个算法封装起来,并且使它们之间可以相互切换。

一般模式
public class MyClass {
    public static void main(String [] args) {
        Context context = new Context(new ConcreteStrategy());
        context.method();
    }
}
interface Strategy {
    public void method();
}

class ConcreteStrategy implements Strategy {

@Override
public void <span class="hljs-function"><span class="hljs-title">method</span></span>() {
    System.out.println(<span class="hljs-string">"this is first method"</span>);
}

}
class ConcreteStrategy2 implements Strategy {

@Override
public void <span class="hljs-function"><span class="hljs-title">method</span></span>() {
    System.out.println(<span class="hljs-string">"this is second method"</span>);
}

}
class Context {
private Strategy strategy;

public Context(Strategy strategy) {
    this.strategy = strategy;
}
public void <span class="hljs-function"><span class="hljs-title">method</span></span> () {
    this.strategy.method();
}

}

复制代码
  • Strategy: 抽象策略角色,提供一个接口,定义所有策略要实现的方法和属性
  • ConcreteStrategy:具体策略角色,实现 Strategy,是想具体的方法
  • Context 封装角色,屏蔽高层模块策略,算法的直接访问。
优点
  • 可以动态的改变对象的行为,扩展性良好。
缺点
  • 策略类数量多
  • 所有策略必须可知
适用场景
  • 算法需要自由切换的场景
  • 需要屏蔽算法规则的场景
  • 多个类只在行为或算法上稍有不懂的场景
3. 访问者模式

定义:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

一般模式
public class MyClass {
    public static void main(String [] args) {
        List<Element> list = ObjectStruture.createElement();
        for (Element element: list) {
            element.accept(new ConcreteVisitor());
        }
    }
}
// 抽象元素类
abstract class Element {
    public abstract void accept(Visitor visitor);
    public abstract void doSomething();
}
// 抽象访问者
interface Visitor {
    public void visit(ConcreteElement1 element1);
    public void visit(ConcreteElement2 element2);
}
class ConcreteElement1 extends Element {
@Override
public void accept(Visitor visitor) {
    visitor.visit(this);
}

@Override
public void <span class="hljs-function"><span class="hljs-title">doSomething</span></span>() {
    System.out.println(<span class="hljs-string">"this is first element"</span>);
}

}
class ConcreteElement2 extends Element {

@Override
public void accept(Visitor visitor) {
    visitor.visit(this);
}

@Override
public void <span class="hljs-function"><span class="hljs-title">doSomething</span></span>() {
    System.out.println(<span class="hljs-string">"this is second element"</span>);
}

}
class ConcreteVisitor implements Visitor {

@Override
public void visit(ConcreteElement1 element1) {
    element1.doSomething();
}

@Override
public void visit(ConcreteElement2 element2) {
    element2.doSomething();
}

}
class ObjectStruture {
public static List<Element> createElement () {
List<Element> list = new ArrayList<>();
Random random = new Random();
for (int i = 0;i< 5; i++) {
int j = random.nextInt(50);
if (j > 25) {
list.add(new ConcreteElement1());
} else {
list.add(new ConcreteElement2());
}
}
return list;
}
}

复制代码
  • Element:抽象元素类,一般提供两类方法,一种是自身的业务逻辑,另外就是允许接收哪类访问者来访问
  • Visitor:抽象访问者,抽象类或者接口,声明访问哪些元素
  • ConcreteElement: 访问者,实现抽象访问者所声明的方法
  • ConcreteVistor: 元素类,是想抽象元素的所声明的 accpect 方法。
优点
  • 符合单一职责原则
  • 扩展性良好,灵活度高
缺点
  • 具体元素变更比较困难
  • 违背了依赖倒置原则
适用场景
  • 一个对象中存在着一些与本对象不相干的操作,为了避免这些操作污染这个对象。可以使用访问者模式
  • 一组对象中,寻在这相似的操作,为了避免大量重复代码,可以使用访问者模式
4. 中介者模式

定义:用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互交互,从而使期耦合松散,并且可以独立地改变它们之间的交互。

中介者模式其实就是将网状的用户关系模型改编成星形的用户关系模型。

一般模式
public class MyClass {
    public static void main(String [] args) {
        ConcreteColleagueA coA = new ConcreteColleagueA();
        ConcreteColleagueB coB = new ConcreteColleagueB();
                Mediator mediator = new ConcreteMediator(coA, coB);
        coA.setNumber(1000, mediator);
        System.out.println("----coA--" + coA.getNumber());
        System.out.println("----coB--"+ coB.getNumber());
        coB.setNumber(1000, mediator);
        System.out.println("----coA--" + coA.getNumber());
        System.out.println("----coB--"+ coB.getNumber());
    }
}
abstract class Colleague {
    protected int number = 0;
public int <span class="hljs-function"><span class="hljs-title">getNumber</span></span>() {
    <span class="hljs-built_in">return</span> number;
}

public void <span class="hljs-built_in">set</span>Number(int number) {
    this.number = number;
}
    abstract public void <span class="hljs-built_in">set</span>Number(int number, Mediator mediator);

}
class ConcreteColleagueA extends Colleague {

@Override
public void <span class="hljs-built_in">set</span>Number(int number, Mediator mediator) {
    this.number = number;
    mediator.AaffectB();
}

}
class ConcreteColleagueB extends Colleague {

@Override
public void <span class="hljs-built_in">set</span>Number(int number, Mediator mediator) {
    this.number = number;
    mediator.BaffectA();
}

}
abstract class Mediator {
protected ConcreteColleagueA coA;
protected ConcreteColleagueB coB;

public Mediator(ConcreteColleagueA coA, ConcreteColleagueB coB) {
    this.coA = coA;
    this.coB = coB;
}
public abstract void AaffectB();
public abstract void BaffectA();

}

class ConcreteMediator extends Mediator {

public ConcreteMediator(ConcreteColleagueA coA, ConcreteColleagueB coB) {
    super(coA, coB);
}

@Override
public void <span class="hljs-function"><span class="hljs-title">AaffectB</span></span>() {
    int number = coA.getNumber();
    coB.setNumber(number * 100);
}

@Override
public void <span class="hljs-function"><span class="hljs-title">BaffectA</span></span>() {
    int number = coB.getNumber();
    coA.setNumber(number * 2);
}

}

复制代码
  • Colleague: 同事类,提供一个方法,使得其属性的变化和中介者相关联
  • Mediator: 抽象中介者,定义统一的接口,用于各同事直接通信
  • ConcreteMediator: 通过协调各同事实现协同行为,因此必须依赖各个同事角色。
  • Colleague: 同事类,提供一个方法,使得其属性的变化和中介者相关联
  • Mediator: 抽象中介者,定义统一的接口,用于各同事直接通信
  • ConcreteMediator: 通过协调各同事实现协同行为,因此必须依赖各个同事角色。
5. 状态模式

定义:当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。

一般模式
public class MyClass {
    public static void main(String [] args) {
        Context context = new Context();
        context.setState(new ConcreteState1());
        context.method2();
    }
}
abstract class State {
    protected Context context;
public void <span class="hljs-built_in">set</span>Context(Context context) {
    this.context = context;
}

public abstract void method1();
public abstract void method2();

}
class Context {
private State currState;

protected static final ConcreteState1 state1 = new ConcreteState1();
protected static final ConcreteState2 state2 = new ConcreteState2();
public void <span class="hljs-built_in">set</span>State(State state) {
    this.currState = state;
    this.currState.setContext(this);
}
public void <span class="hljs-function"><span class="hljs-title">method1</span></span>() {
    this.currState.method1();
}
public void <span class="hljs-function"><span class="hljs-title">method2</span></span>() {
    this.currState.method2();
}

}

class ConcreteState1 extends State {

@Override
public void <span class="hljs-function"><span class="hljs-title">method1</span></span>() {
    System.out.println(<span class="hljs-string">"this is first method"</span>);
}

@Override
public void <span class="hljs-function"><span class="hljs-title">method2</span></span>() {
    super.context.setState(Context.state2);
    super.context.method2();
}

}

class ConcreteState2 extends State {

@Override
public void <span class="hljs-function"><span class="hljs-title">method1</span></span>() {
    super.context.setState(Context.state1);
    super.context.method1();
}

@Override
public void <span class="hljs-function"><span class="hljs-title">method2</span></span>() {
    System.out.println(<span class="hljs-string">"this is second method"</span>);
}

}

复制代码
  • State: 抽象状态类,负责对象状态定义,并且封装环境角色以实现状态切换。
  • ConcreteState:具体状态角色,完成本状态下要做的事情以及如何过渡到其他状态
  • Context:环境角色,负责具体的状态切换
优点
  • 结构清晰,封装性好
缺点
  • 环境类中角色自类太多,不好管理
适用场景
  • 行为随状态改变而改变的场景
  • 条件、分支判断语句的替代者
6. 备忘录模式

定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

一般模式
public class MyClass {
    public static void main(String [] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();
        originator.setState("你好吗");
        caretaker.setMemento(originator.createMemento());
        // 改变状态
        originator.setState("你还好吗");
        // 回复原来状态
        originator.restoreMementor(caretaker.getMemento());
        System.out.println(originator.getState());
    }
}
/*
* 备忘录角色
* 备份、存储原有数据
* */
class Memento {
    private String state = "";
public Memento(String state) {
    this.state = state;
}

public void <span class="hljs-built_in">set</span>State(String state) {
    this.state = state;
}

public String <span class="hljs-function"><span class="hljs-title">getState</span></span>() {
    <span class="hljs-built_in">return</span> state;
}

}
/*
* 备忘录发起类
* 备忘录中存储的就是该类的内容
* */
class Originator {
private String state = "";

public String <span class="hljs-function"><span class="hljs-title">getState</span></span>() {
    <span class="hljs-built_in">return</span> state;
}

public void <span class="hljs-built_in">set</span>State(String state) {
    this.state = state;
}
public Memento <span class="hljs-function"><span class="hljs-title">createMemento</span></span>() {
    <span class="hljs-built_in">return</span> new Memento(this.state);
}
public void  restoreMementor(Memento memento) {
    this.setState(memento.getState());
}

}
/*
* 备忘录管理类
* 对备忘录进行管理,存储
* */
class Caretaker {
private Memento memento;

public Memento <span class="hljs-function"><span class="hljs-title">getMemento</span></span>() {
    <span class="hljs-built_in">return</span> memento;
}

public void <span class="hljs-built_in">set</span>Memento(Memento memento) {
    this.memento = memento;
}

}

复制代码
多状态多备份备忘录

通常情况下,Originator 类一般是一个 JavaBean,而需要保存的状态不止一个,需要备份数量也不止一个,这就是所谓的多状态多备份备忘录,就像下面代码:

public class MyClass {
   public static void main(String [] args) {
       Originator originator = new Originator();
       Caretaker caretaker = new Caretaker();
       originator.setState1("我是谁");
       originator.setState2("我在哪");
       originator.setState3("我在干嘛");
       caretaker.setMemento("01", originator.createMemento());
       originator.setState1("hahhaha");
       originator.setState2("我在家");
       originator.setState3("ouh;");
       originator.restoreMementor(caretaker.getMemento("01"));
       System.out.println("------ 恢复之后的状态 --" + originator);
   }
}
/*
* 备忘录角色
* 备份、存储原有数据
* */
class Memento {
   private Map<String, Object> stateMap;

public Memento(Map<String, Object> stateMap) {
this.stateMap = stateMap;
}

public Map<String, Object> getStateMap() {
return stateMap;
}

public void setStateMap(Map<String, Object> stateMap) {
this.stateMap = stateMap;
}
}
class BeanUtils {
public static Map<String, Object> backupProp(Object bean) {
Map<String, Object> result = new HashMap<>();
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
// 返回 PropertyDescriptor 类型的 javaBean 描述
PropertyDescriptor[] descriptors = (PropertyDescriptor[]) beanInfo.getPropertyDescriptors();
for (PropertyDescriptor des : descriptors) {
String fieldName = des.getName();
// 读取属性的方法
Method method = des.getReadMethod();
// 读取属性值
Object fieldValue = method.invoke(bean, new Object[]{});
if (!fieldName.equalsIgnoreCase(“class”)) {
result.put(fieldName, fieldValue);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}

public static void restoreProp(Object bean, Map<String, Object> propMap) {
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
// 获取 PropertyDescriptor 的对象数组
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
// 增强for循环,遍历所有的属性,设置到 bean 中
for(PropertyDescriptor des: descriptors){
// 获取 key 值对象
String fieldName = des.getName();
if(propMap.containsKey(fieldName)){
Method setter = des.getWriteMethod();
setter.invoke(bean, new Object[]{propMap.get(fieldName)});
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*
* 备忘录发起类
* 备忘录中存储的就是该类的内容
* */
class Originator {
private String state1 = ““;
private String state2 = ””;
private String state3 = "";

public String getState1() {
return state1;
}

public String getState2() {
return state2;
}

public String getState3() {
return state3;
}

public void setState1(String state1) {
this.state1 = state1;
}

public void setState2(String state2) {
this.state2 = state2;
}

public void setState3(String state3) {
this.state3 = state3;
}

public Memento createMemento() {
return new Memento(BeanUtils.backupProp(this));
}
public void restoreMementor(Memento memento) {
BeanUtils.restoreProp(this, memento.getStateMap());
}

@Override
public String toString() {
return “Originator{” +
“state1=’” + state1 + ‘'’ +
“, state2=’
” + state2 + ‘'’ +
, state3=’” + state3 + ‘<span class=“hljs-string”>’‘ +
’}’;
}
}
/*
* 备忘录管理类
* 对备忘录进行管理,存储
* */
class Caretaker {
private Map<String, Memento> map = new HashMap<String, Memento>();
public Memento getMemento(String index){
return map.get(index);
}

public void setMemento(String index, Memento memento){
this.map.put(index, memento);
}
}

复制代码
优点
  • 可以回滚操作
  • 发起人不用分别对每个备份状态进行管理
缺点
  • 对资源的消耗比较大
适用场景
  • 在需要回滚操作的情况下
7. 责任链模式

定义:使多个对象都有机会处理请求,从而避免了发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理该请求为止。

举个例子:比如我们去部门去办理某项手续,你去的地方不能办理,他会转交给下个部门,如果下个部门也不能办理的话,还会转交给其他部门,直到给能办理的部门。

一般模式
public class MyClass {
    public static void main(String [] args) {
        Handler handler1 = new ConcreteHandler();
        Handler handler2 = new ConcreteHandler();
        handler1.setSuccessor(handler2);
        handler1.handleRequest();
    }
}

abstract class Handler {
protected Handler successor;

public Handler <span class="hljs-function"><span class="hljs-title">getSuccessor</span></span>() {
    <span class="hljs-built_in">return</span> successor;
}

public void <span class="hljs-built_in">set</span>Successor(Handler successor) {
    this.successor = successor;
}
public abstract void handleRequest();

}

class ConcreteHandler extends Handler {

@Override
public void <span class="hljs-function"><span class="hljs-title">handleRequest</span></span>() {
    <span class="hljs-keyword">if</span> (getSuccessor() != null) {
        getSuccessor().handleRequest();
    } <span class="hljs-keyword">else</span> {
        System.out.println(<span class="hljs-string">"我来处理"</span>);
    }
}

}

复制代码
  • 抽象处理者角色 (Handler):定义出一个处理请求的接口。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。这个角色通常由一个 Java 抽象类或者 Java 接口实现。
  • 具体处理者角色 (ConcreteHandler):具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
优点
  • 灵活度高,两者解耦
缺点
  • 调试不方便
8. 模版方法模式

定义:定义一个操作中的算法框架,而将一些步骤延迟到子类中,子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

举个例子:比如我们去银行取办理业务,一般的流程是取号,然后办理业务,然后给办理员做出评价。取号和评价都是基本要做的,但是其中的办理业务就会出现各种不同。

public class MyClass {
    public static void main(String [] args) {
        AbstractBank b1 = new ConcreteDeposit();
        b1.process();
        AbstractBank b2 = new ConcreteTrancfer();
        b2.process();
    }
}
abstract class AbstractBank {
    public void takeNumber() {
        System.out.println("取号");
    }
    public void evaluateHook () {
        System.out.println("评价操作员");
    }
    public abstract void transact();
    public void process (){
        this.takeNumber();
        this.transact();
        this.evaluateHook();
    }
}
class ConcreteDeposit extends AbstractBank {
@Override
public void <span class="hljs-function"><span class="hljs-title">transact</span></span>() {
    System.out.println(<span class="hljs-string">"存款"</span>);
}

}
class ConcreteTrancfer extends AbstractBank {

@Override
public void <span class="hljs-function"><span class="hljs-title">transact</span></span>() {
    System.out.println(<span class="hljs-string">"转账"</span>);
}

}

复制代码
优点
  • 形式定义算法,具体细节由子类实现
  • 代码复用
适用场景
  • 多个子类有共有的方法,并且逻辑基本相同
  • 重复复杂的算法,可以把核心算法设计为模版方法,具体细节由子类去实现
  • 控制子类扩展
9. 迭代器模式

定义:提供一种方法访问一个容器对象中各个元素,而不是暴露该对象的内容细节。

一般模式
public class MyClass {
    public static void main(String [] args) {
        Aggregate aggregate = new ConcreteAggregate();
        aggregate.add("王二");
        aggregate.add("李五");
        aggregate.add("赵四");
        Iterator iterator = aggregate.iterator();
        while (iterator.hasNext()) {
            String object = (String) iterator.next();
            System.out.println(object);
        }
    }
}

interface Iterator {
public Object next();
public boolean hasNext();
}

class ConcreteIterator implements Iterator {
private List list = new ArrayList();
private int cursor = 0;
public ConcreteIterator(List list) {
this.list = list;
}

@Override
public Object <span class="hljs-function"><span class="hljs-title">next</span></span>() {
    Object object = null;
    <span class="hljs-keyword">if</span> (hasNext()) {
        object = list.get(cursor ++);
    }
    <span class="hljs-built_in">return</span> object;
}

@Override
public boolean <span class="hljs-function"><span class="hljs-title">hasNext</span></span>() {
    <span class="hljs-keyword">if</span> (list.size() == cursor) {
        <span class="hljs-built_in">return</span> <span class="hljs-literal">false</span>;
    }
    <span class="hljs-built_in">return</span> <span class="hljs-literal">true</span>;
}

}

interface Aggregate {
public void add(Object object);
public void remove(Object object);
public Iterator iterator();
}

class ConcreteAggregate implements Aggregate {
private List list = new ArrayList();

@Override
public void add(Object object) {
    list.add(object);
}

@Override
public void remove(Object object) {
    list.remove(object);
}

@Override
public Iterator <span class="hljs-function"><span class="hljs-title">iterator</span></span>() {
    <span class="hljs-built_in">return</span> new ConcreteIterator(list);
}

}

复制代码
  • Iterator: 抽象迭代器,定义遍历元素所需要的方法,
  • ConcreteIterator: 迭代器的实现类,实现定义的方法,完成集合的迭代。
  • Aggregate:抽象容器,提供 iterator()方法。
  • ConcreteAggregate: 抽象容器实现类。
优点
  • 简化遍历方式
  • 封装性良好
缺点
  • 对于简单的遍历,可能使用起来会比较繁琐。
10. 命令模式

定义: 将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或记录请求日志,可以提供命令的撤销和恢复功能。

一般模式
public class MyClass {
    public static void main(String [] args) {
        Invoker invoker = new Invoker(new ConcreteCommand(new ConcreteReceiver()));
        invoker.action();
    }
}
/*
*   接收者,真正执行命令的对象
* */
abstract class Receiver {
    public abstract void method();
}
class ConcreteReceiver extends Receiver {
@Override
public void <span class="hljs-function"><span class="hljs-title">method</span></span>() {
    System.out.println(<span class="hljs-string">"this is a method"</span>);
}

}
/*
* 定义命令的接口。声明执行的方法
* */
interface Command {
public void execute();
}
class ConcreteCommand implements Command {
private Receiver receiver ;

public ConcreteCommand(Receiver receiver) {
    this.receiver = receiver;
}

@Override
public void <span class="hljs-function"><span class="hljs-title">execute</span></span>() {
    this.receiver.method();
}

}
/*
* 要求命令执行请求,持有命令对象
* */
class Invoker {
private Command command;

public Invoker(Command <span class="hljs-built_in">command</span>) {
    this.command = <span class="hljs-built_in">command</span>;
}
public void <span class="hljs-function"><span class="hljs-title">action</span></span>() {
    this.command.execute();
}

}

复制代码

命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的职责分隔开。

11. 解释器模式

定义:给定一个语言,定义它的文法的一种表示,并表示一个解释器,这个解释器使用该表示来解释语言中的句子。

解释器模式,在 Android 中用到的不多,但是也可以简单了解一下。 举一个加减乘除的例子

public class MyClass {
    public static void main(String [] args) {
        Expression ex ;
    Context con ;
    con = new Context();

    //设置变量、常量

    Variable a = new Variable();

    Variable b = new Variable();

    Constant c = new Constant(4);

// 为变量赋值

    con.addValue(a , 8);

    con.addValue(b , 9);

// 运算,对句子的结构由我们自己来分析,构造

    ex = new Division(new Multiply(a , b), new Add(new Subtract(a , b) , c));

    System.out.println(<span class="hljs-string">"运算结果为:"</span>+ex.interpret(con));
}

}

class Context

{

private Map valueMap = new HashMap();

public void addValue(Variable x , int y)

{

    Integer yi = new Integer(y);

    valueMap.put(x , yi);

}

public int LookupValue(Variable x)

{

    int i = ((Integer)valueMap.get(x)).intValue();

    <span class="hljs-built_in">return</span> i ;

}

}

abstract class Expression {
public abstract int interpret(Context con);
}
// 终结符表达式角色

class Constant extends Expression

{

private int i ;

public Constant(int i)

{
    this.i = i;
}

public int interpret(Context con)

{
    <span class="hljs-built_in">return</span> i ;
}

}
class Variable extends Expression

{

public int interpret(Context con)

{
    //this为调用interpret方法的Variable对象

    <span class="hljs-built_in">return</span> con.LookupValue(this);

}

}
// 非终结符表达式角色

class Add extends Expression

{

private Expression left ,right ;

public Add(Expression left , Expression right)

{

    this.left = left ;

    this.right= right ;

}

public int interpret(Context con)

{

    <span class="hljs-built_in">return</span> left.interpret(con) + right.interpret(con);

}

}
class Subtract extends Expression

{

private Expression left , right ;

public Subtract(Expression left , Expression right)

{

    this.left = left ;

    this.right= right ;

}

public int interpret(Context con)

{

    <span class="hljs-built_in">return</span> left.interpret(con) - right.interpret(con);

}

}
class Multiply extends Expression

{

private Expression left , right ;

public Multiply(Expression left , Expression right)

{

    this.left = left ;

    this.right= right ;

}

public int interpret(Context con)

{

    <span class="hljs-built_in">return</span> left.interpret(con) * right.interpret(con);

}

}
class Division extends Expression

{

private Expression left , right ;

public Division(Expression left , Expression right)

{
    this.left = left ;
    this.right= right ;
}

public int interpret(Context con)

{
    try{
        <span class="hljs-built_in">return</span> left.interpret(con) / right.interpret(con);

    }catch(ArithmeticException ae)

    {
        System.out.println(<span class="hljs-string">"被除数为0!"</span>);
        <span class="hljs-built_in">return</span> -11111;
    }

}

}

复制代码
  • 抽象表达式 (Expression) 角色:声明一个所有的具体表达式角色都需要实现的抽象接口。这个接口主要是一个 interpret() 方法,称做解释操作。

  • 终结符表达式 (Terminal Expression) 角色:实现了抽象表达式角色所要求的接口,主要是一个 interpret() 方法;文法中的每一个终结符都有一个具体终结表达式与之相对应。比如有一个简单的公式 X=Y+Z,在里面 R1 和 R2 就是终结符,对应的解析 Y 和 Z 的解释器就是终结符表达式。

  • 非终结符表达式 (Nonterminal Expression) 角色:文法中的每一条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式 X=Y-Z 中,“-" 就是非终结符,解析“+”的解释器就是一个非终结符表达式。

  • 环境 (Context) 角色:这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如 X=Y+Z,我们给 Y 赋值 2,给 Y 赋值 3。这些信息需要存放到环境角色中,很多情况下我们使用 Map 来充当环境角色就足够了

二、总结

设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。在 Android 的源码中也会经常会出现设计模式的影子,在这里我把所有的设计模式都简单的一一介绍了,并没有深入的去探究,有需要或者有兴趣的可以自己去深入研究一下,者对我们来说也是有益无害的。

参考资料

设计模式(五)观察者模式

《Android 源码设计模式》

《大话设计模式》

推荐阅读

如何正确地使用设计模式

  • Android

    开放手机联盟(一个由 30 多家科技公司和手机公司组成的团体)已开发出 Android,Android 是第一个完整、开放、免费的手机平台。

    293 引用
感谢    赞同    分享    收藏    关注    反对    举报    ...