分类(常见的设计模式)
1.创建型模式
a) 工厂模式
b) 抽象工厂模式
c) 单例模式
d) 建造者模式
2.结构型模式
a) 适配器模式
b) 装饰器模式
c) 桥接模式
d) 代理模式
3.行为型模式
a) 命令模式
b) 迭代器模式
c) 策略模式
d) 观察者模式
六大原则
1、开闭原则
对扩展开放,对修改关闭。
2、里氏代换原则
任何基类可以出现的地方,子类一定可以出现。
3、依赖倒转原则
依赖于抽象而不依赖于具体。
4、接口隔离原则
使用多个隔离的接口,比使用单个接口要好。
5、迪米特法则,又称最少知道原则
一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则
尽量使用合成/聚合的方式,而不是使用继承。
一、工厂模式
作用
一个抽象的接口,多个抽象接口的实现类,一个工厂,用来实例化抽象的接口。
优点
一个调用者想创建一个对象,直接向工厂请求即可,不需要知道具体实现,以提高系统的可维护性、可扩展性。
缺点
产品修改时,工厂也要进行修改。
代码
二、抽象工厂模式
作用
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。
优点
当一个产品类型(每一类中有多个产品)被设计成一起工作时,有良好的维护性。
缺点
产品类扩展困难。
例
三、单例模式
作用
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
特点
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
懒汉式
线程不安全
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
线程安全
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
双检锁
public class Singleton {
private static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
静态内部类
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
饿汉式
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
四、建造者模式
作用
建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。
应用实例
肯德基里,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。
角色
抽象建造者角色:一个抽象接口,以规范产品对象的各个组成成分的建造。
具体建造者角色:实现抽象建造者Builder所声明的接口,给出一步一步地完成创建产品实例的操作。
导演者角色:担任这个角色的类调用具体建造者角色以创建产品对象。应当指出的是,导演者角色并没有产品类的具体知识,真正拥有产品类的具体知识的是具体建造者角色。
产品角色:产品便是建造中的复杂对象。一般来说,一个系统中会有多于一个的产品类,而且这些产品类并不一定有共同的接口,而完全可以是不相关联的。
例子
五、适配器模式
作用
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
模式中的角色
1.目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
2.需要适配的类(Adaptee):需要适配的类或适配者类。
3.适配器(Adapter):实现了目标接口,通过包装一个需要适配的对象,把原接口转换成目标接口。
通过适配器把需要适配的类转成目标类
优点
- 接口可以转成自己希望的另一个接口
- 提高了类的复用。
缺点
过多地使用适配器,会让系统非常零乱,不易整体进行把握。
例子
六、装饰者模式
作用
对已有的业务逻辑进一步的封装,使其增加额外的功能。即向一个现有的对象添加新的功能,同时又不改变其结构。
优点
可以提供比继承更多的灵活性。
缺点
多层装饰比较复杂。
例子
实物基类
鸡肉
鸭肉
装饰者基类
蒸-装饰者
烤-装饰者
七、桥接模式
作用
将抽象部分与实现部分分离,使它们都可以独立的变化。把两个角色之间的继承关系改为了耦合的关系。
例子
八、代理模式
作用
一个类代理另一个类的功能。
模式中的角色
- 抽象角色:声明真实对象和代理对象的共同接口。
2. 代理角色:代理对象角色内部含有对真实对象的引用,继承了抽象对象。
3. 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
缺点
由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
例子
九、命令模式
作用
将一个命令封装成一个对象,可以对命令接受者进行不同的命令处理。
组成
命令接受者:执行命令的对象。
命令:操作命令接受者执行命令。
命令对象入口:要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。
例子
十、迭代器模式
作用
这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。
通过容器获取迭代器,通过迭代器遍历元素。
角色
1.迭代器接口
2.迭代器具体实现
3.抽象容器
4.具体容器
例子
迭代器接口
public interface Iterator {
public Object first();
public Object previous();
public Object next();
public boolean hasNext();
}
具体迭代器
public class MyIterator implements Iterator{
private List<Object> list;
private int index = 0;
public MyIterator(List<Object> list) {
this.list = list;
}
@Override
public Object previous() {
if((this.index - 1) < 0){
return null;
}else{
return this.list.get(--index);
}
}
@Override
public Object next() {
if((this.index + 1) >= this.list.size()){
return null;
}else{
return this.list.get(++index);
}
}
@Override
public boolean hasNext() {
if(this.index < (this.list.size() - 1)){
return true;
}
return false;
}
@Override
public Object first() {
if(this.list.size() <= 0){
return null;
}else{
return this.list.get(0);
}
}
}
容器接口
package com.pichen.dp.behavioralpattern.iterator;
public abstract class Container {
public abstract Iterator iterator();
public abstract void put(Object obj);
}
具体容器
public class MyContainer extends Container{
private List<Object> list;
public MyContainer() {
this.list = new ArrayList<Object>();
}
@Override
public void put(Object obj){
this.list.add(obj);
}
@Override
public Iterator iterator() {
return new MyIterator(list);
}
}
十一、策略模式
作用
将多个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。
组成
1.抽象策略角色:通常由一个接口或者抽象类实现。
2.具体策略角色: 包装了相关的算法和行为。
3.环境角色: 持有一个策略类的引用,最终给客户端调用。
实际举例
旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。
例子
十二、观察者模式
作用
它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
优点
1.观察者模式在被观察者和观察者之间建立一个抽象的耦合。
2.观察者模式支持广播通讯。被观察者会向所有的登记过的观察者发出通知。
缺点
1.如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2.如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3.观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
结构图
- Subject:抽象主题(抽象被观察者),每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
- ConcreteSubject:具体主题(具体被观察者),把所有观察者对象保存在一个集合里,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
- Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
- ConcrereObserver:具体观察者,是实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
例子