java设计模式大全(精简版),个人知识梳理

设计模式三大分类:

创建型模式


一、Singleton,单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点

二、Abstract Factory,抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。

三、Factory Method,工厂方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类。

四、Builder,建造模式:将一个复杂对象的构建与他的表示相分离,使得同样的构建过程可以创建不同的表示。

五、Prototype,原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。

结构型模式


六、Iterator,迭代器模式:提供一个方法顺序访问一个聚合对象的各个元素,而又不需要暴露该对象的内部表示。

七、Observer,观察者模式:定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。

八、Template Method,模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤。

九、Command,命令模式:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志,以及支持可撤销的操作。

十、State,状态模式:允许对象在其内部状态改变时改变他的行为。对象看起来似乎改变了他的类。

十一、Strategy,策略模式:定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。

十二、China of Responsibility,职责链模式:使多个对象都有机会处理请求,从而避免请求的送发者和接收者之间的耦合关系

十三、Mediator,中介者模式:用一个中介对象封装一些列的对象交互。

十四、Visitor,访问者模式:表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这个元素的新操作。

十五、Interpreter,解释器模式:给定一个语言,定义他的文法的一个表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

十六、Memento,备忘录模式:在不破坏对象的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

行为型模式


十七、Composite,组合模式:将对象组合成树形结构以表示部分整体的关系,Composite使得用户对单个对象和组合对象的使用具有一致性。

十八、Facade,外观模式:为子系统中的一组接口提供一致的界面,facade提供了一高层接口,这个接口使得子系统更容易使用。

十九、Proxy,代理模式:为其他对象提供一种代理以控制对这个对象的访问

二十、Adapter,适配器模式:将一类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作那些类可以一起工作。

二十一、Decrator,装饰模式:动态地给一个对象增加一些额外的职责,就增加的功能来说,Decorator模式相比生成子类更加灵活。

二十二、Bridge,桥模式:将抽象部分与它的实现部分相分离,使他们可以独立的变化。

二十三、Flyweight,享元模式:使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。

1.单例模式(Singleton)


**定义:**保证一个类只有一个实例,并提供一个访问它的全局访问点
静态实例;
私有构造函数;
静态的获取实例方法

创建时机:

**饿汉式:**提前先创建好对象,线程安全,一上来就占内存;

**懒汉式:**用到时创建好对象,线程不安全。多线程中无法保证单例,如果加synchronized,将会付出很大的内存代价。

为了解决饿汉式、懒汉式所带来的缺点可使用最终极的写法:内部类Holder方式(建议使用)

public class SingleTonHolder{
    private static class SingleTonInnerHolder{
       private static SingleTonHolder instance = new SingleTonHolder();
    }
    public static SingleTpnHolder getInstance(){
       return SingleTonInnerHolder.instance;
    }
}

还有一种是双重检查锁方式,这种方式也能解决懒汉式和饿汉式带来的缺点,不过资源消耗过大,不建议使用。

2.工厂模式(Factory)


**分为:**简单工厂、工厂方法、抽象工厂

简单工厂(静态工厂)


工厂所生产的产品通常有相同的父类或接口。

**优点:**根据外界传入的信息(如传入特点意义字符串),创建相应的对象。

缺点:
1、违背单一职责原则、开发封闭原则;

2、因为每当有新的产品都将要修改SimpleFactory;

3、由于工厂类集中了所有实例的创建逻辑,如果工厂出问题将会影响整个系统;

UML:
这里写图片描述

例子:jdbc就是用到简单工厂模式;

工厂方法


定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类。

优点:用户只需要知道产品的具体工厂,无需关系创建过程,甚至不需要具体产品类的类名;在新增产品情况下,只需要添加一个具体产品类和对应的实现工厂,无需对原工厂进行任何修改,很符合“开闭原则”

**缺点:**每增加一个产品就要增加一个具体类和对象实现工厂,数量过多,类数量成倍增加,增加了系统复杂度,同时增加了系统对具体类的依赖。
UML

这里写图片描述

UML实例

这里写图片描述

**实例总结:**想象成一款计划应用,计划分成作息计划、学习计划、锻炼计划。要编辑这些计划使用不同的面板编辑对应于作息面板、学习面板、锻炼面板。客户端如果要创建一个学习计划即可如下操作即可;

IPlan studyPlan = new StudyPanel().write();

如果想创建作息计划只需替换成new SchedulePanel().write()即可;如果突然老板需要在应用中增加一种任务计划,那么只需要添加一个IPlan的实现类TaskPlan和IPanel的一个实现类TaskPanel即可,而无需动原有工厂代码。

抽象工厂


提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。
不可以增加产品,可以增加产品族。
抽象工厂是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

UML实例:
这里写图片描述

工厂应用场景:

这里写图片描述

3.代理模式


组成:
**抽象角色:**通过接口或抽象类声明真实角色实现的业务方法。

**代理角色:**实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。

**真实角色:**实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

**代理分为:**静态代理、动态代理

**静态代理:**由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

**动态代理:**在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。

静态代理实例


Car接口:

public interface Car {
	public void run();
}

Audi车实现Car接口:

public class Audi implements Car{
	@Override
	public void run() {
		System.out.println("Audi on the way.");		
	}
}

我的车辆代理类:

public class MyCarProxy implements Car{
	private Car car;
	public MyCarProxy(Car car){
		this.car = car;
	}
	@Override
	public void run() {
		System.out.println("myCar first");
		car.run();
		System.out.println("myCar second");
	}
}

客户端:

public class Client {
	public static void main(String[] args) {
		Audi audi = new Audi();
		Car myAudi = new MyCarProxy(audi);
		myAudi.run();
	}
}

输出结果:
myCar first
Audi on the way.
myCar second

动态代理实例


编写一个InvocationHandler的实现类HandleProxy:

public class HandleProxy implements InvocationHandler{
	private Object object;
	public HandleProxy(Object object) {
		this.object = object;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("first");
		Object o = method.invoke(object, args);
		System.out.println("second");
		return o;
	}
}

客户端:

public class Client {
	public static void main(String[] args) {
		Audi audi = new Audi();
		Car a = (Car)Proxy.newProxyInstance(Car.class.getClassLoader(),new Class[]{Car.class}, new HandleProxy(audi));
		a.run();
	}
}

输出结果:
first
Audi on the way.
second

**总结:**从上面可以看出代理模式在不修改原有Audi类的情况下,通过代理类实现了前者和后置功能的添加,和符合开闭原则。
Spring APO 实质上就是利用了动态代理实现的。
应用场景:如日志、记录、

4.适配器模式(Adapter pattern)


将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的哪些类可以一起工作。
好比变压器
**类适配器:**使用对象继承方式,是静态的定义方式;
**对象适配:**器使用对象组合的方式,是动态组合的方式。

优点:
1、可以让任何两个没有关联的类一起运行。

2、提高了类的复用。

3、增加了类的透明度。

4、灵活性好。

缺点:
1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构;

2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

**使用场景:**有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。

**注意事项:**适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。

代码示例:
(下面演示手机220V电压转换成5V电压充电过程)

Power5V接口:

public interface Power5V {
	void getPower5V();
}

Power220V:

public class Power220V {
	public void getPower220V(){
		System.out.println("输出220V电压。");
	}
}

PowerAdapter:

public class PowerAdapter extends Power220V implements Power5V{
	@Override
	public void getPower5V() {
		super.getPower220V();
		transformPrower();
		System.out.println("现在电压5V。");
	}
	private void transformPrower() {
		System.out.println("将220V电压变成5V了。");
	}
	
}

Phone:

public class Phone {
	public void changePrower(Power5V power){
		power.getPower5V();
		System.out.println("手机开始充电。。。");
	}
}

Main:

public class Main {
	public static void main(String[] args) {
		Phone phone = new Phone();
		//没有5V电压情况下,使用适配器,将220V电压转换成5V电压
		phone.changePrower(new PowerAdapter());
	}
}

输出结果:
手机开始充电。。。
输出220V电压。
将220V电压变成5V了。
现在电压5V。

5.观察者模式(Observer Pattern)


当对象间存在一对多关系时,则使用观察者模式。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。

优点:
1、观察者和被观察者是抽象耦合的。

2、建立一套触发机制。

缺点:
1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间;

2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃;

3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

UML:

这里写图片描述

上面表达了一个消息中心的工作流程,如果消息中心MessageControl发送通知,两个观察者ReceiverA、ReceiverB在消息中心注册了,则两个观察者ReceiverA、ReceiverB,将都会收到消息。
具体实例:
接收者需要实现的接口:

public interface Receiver {
	void message(String message);
}

接受者A:

public class ReceiverA implements Receiver {
	@Override
	public void message(String message) {
		System.out.println("I'm ReceiverA :"+message);
	}
}

接受者B:

public class ReceiverB implements Receiver {
	@Override
	public void message(String message) {
		System.out.println("I'm ReceiverB :"+message);
	}
}

消息中心:

public class MessageControl {
	private List<Receiver> receiverList = new ArrayList<>();
	private String message = "123";
	public void registerReceiver(Receiver receiver){
		receiverList.add(receiver);
	}
	public void removeReceiver(Receiver receiver){
		receiverList.remove(receiver);
	}
	
	public void noticeMessage(){
		for(Receiver receiver:receiverList){
			receiver.message(message);
		}
	}
	
	public void setMessage(String message) {
		this.message = message;
		noticeMessage();
	}
}

测试主类:

public class Main {
	public static void main(String[] args) {
		ReceiverA rA = new ReceiverA();
		ReceiverB rB = new ReceiverB();
		MessageControl msgControl = new MessageControl();
		msgControl.registerReceiver(rA);
		msgControl.setMessage("系统故障,给您带来不便请谅解。");
		//将ReceiverB也注册
		msgControl.registerReceiver(rB);
		msgControl.setMessage("今天系统会员买一年送一年,机不可失失不再来。");
	}
}

运行结果:
I’m ReceiverA :系统故障,给您带来不便请谅解。
I’m ReceiverA :今天系统会员买一年送一年,机不可失失不再来。
I’m ReceiverB :今天系统会员买一年送一年,机不可失失不再来。

总结:
观察者模式属于结构型模式之一,在很多场景会使用到,如在android开发中,数据中从网络中得到,这时要同时更新多个Activity,这是观察者模式就派上用场了。在android中各种监听器实质上就用到了观察者模式。当然在其它客户端、web端等都会用到,看具体场景使用。

6.策略模式


定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。
优点:
1、算法可以自由切换。

2、避免使用多重条件判断。

3、扩展性良好。

缺点:
1、策略类会增多;

2、所有策略类都需要对外暴露。

使用场景:
1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。

2、一个系统需要动态地在几种算法中选择一种。

3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

**注意事项:**如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。

下面以小明出游选择交通工具为例,小明可以通过火车、飞机进行出游,当然你也可以增加其它交通工具,都不会影响原有代码,只需实现Conveyance接口即可。和符合开闭原则。

UML:
这里写图片描述

Conveyance接口:

public interface Conveyance {
	void process();
}

交通工具火车:

public class Train implements Conveyance{
	@Override
	public void process() {
		System.out.println("我正在坐着上火车去西藏。");
	}
}

交通工具飞机:

public class Plane implements Conveyance {
	@Override
	public void process() {
		System.out.println("我正在坐着飞机去西藏。");
	}
}

小明:

public class XiaoMing {
	public void journey(Conveyance c){
		c.process();
	}
}

主类:

public class Main {
	public static void main(String[] args) {
		XiaoMing xm = new XiaoMing();
		xm.journey(new Train());
		xm.journey(new Plane());
	}
}

运行结果:
我正在坐着上火车去西藏。
我正在坐着飞机去西藏。
上面代码中可以看出,小明要使用不同交通工具去旅游,并不会对小明的代码发生改变。

7.混合模式


MVC:


这个就不多说,SpringMVC、Struts/Struts2这些都是MVC的框架,以及android开发整体就一个MVC的框架存在等等。

**优点:**分工明确、松耦合、重用性高

**缺点:**View和Model耦合相对较高。

结构关系图:
这里写图片描述

MVP:


从经典的模式MVC演变而来,它们基本思想有相通的地方:
Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。

优点:
1、模型与视图完全分离;

2、可以更高效地使用模型,所有交互发生子Presenter内部;

3、一个Presenter可用于多个视图;

4、如果逻辑放在Presenter中,就可以脱离用户接口进行单元测试。
View不再直接访问Model。

**缺点:**要定义过多的接口,增加了代码复杂度;Presenter与视图交互会过于频繁。

结构关系图:
这里写图片描述

8.反模式


这里写图片描述
这里写图片描述
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值