设计模式 Java Design Pattern

1.设计模式(Design Pattern)23

按目的准则分类:

创建型(creational) 5 与对象的创建有关

Singleton Prototype FactoryMethod AbstractFactory Builder

结构型(structural) 7 处理类与对象的组合

Adapter Decorator Composite Proxy
Bridge Facade Flyweitht

行为型(behavioral) 11 对类或对象怎样交互和怎样分配职责进行描述

TemplateMethod Strategy Observer
Interpreter Chain of Responsibility Command
Iterator Mediator Memento State Visitor

2.功能介绍

创建型

模式 功能
单例 确保有且只有一个对象被创建保证一个类仅有一个实例,并提供一个访问它的全局访问点
原型 用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象
工厂方法 定义一个用于创建对象的接口,让子类决定将哪一个类实例化FactoryMehtod使一个类的实例化延迟到其子类
抽象工厂 提供一个创建一系列相关或相互依赖对象的接口,无需指定他们具体的类
建造者 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

结构型

模式 功能
装饰者 包装一个对象,以提供新的行为 动态地给一个对象添加一些额外的职责,就扩展功能而言,比生成子类方式更灵活
适配器 封装对象,并提供不同的接口 将一个类的接口转换成客户希望的另外一个接口,该模式使得原本由于接口不兼容而不能一起工作的类可以一起工作
代理 包装对象,以控制对此对象的访问 为目标对象提供一个代理以控制对这个对象的访问
门面 简化一群类的接口 为子系统中的一组接口提供一个一致的界面 定义了一个高层接口,这个接口使得这一子系统更加容易使用
组合 客户用一致的方法处理对象集合和单个对象 将对象组合成树形结构以表示“部分-整体”的层次结构,它使得客户对单个对象和复合对象的使用具有一致性
桥接 将抽象部分与它的实现部分分离,使它们都可以独立地变化
享元 运用共享技术有效地支持大量细粒度的对象

行为型

模式 功能
策略 封装可以互换的行为,并使用委托来决定要使用哪一个 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换 该模式使得算法的变化可独立于使用它的客户
迭代器 在对象的集合中游走,而不暴露集合的实现 提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示
状态 封装了基于状态的行为,并使用委托在行为之间切换 允许一个对象在其内部状态改变时,改变它的行为,对象看起来似乎修改了它所属的类
观察者 让对象能够在状态改变时被通知 定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新
模板方法 由子类决定如何实现一个算法中的步骤 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中 该模式使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤
命令 封装请求成为对象
中介 用一个中介对象来封装一系列的对象交互 中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立的改变它们之间的交互
备忘录 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后可将该对象恢复到保存的状态
解析器 给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子
责任链 为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它
访问者 表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作

3.设计原则(Seven Principles of Design Patterns)

原则 解释
开闭 一个软件实体应该对扩展开发,对修改闭合
里氏代换 任何能使用父类的地方一定能使用子类
依赖倒转 要依赖于抽象,不要依赖于实现,或者使抽象不应该依赖于细节,细节应该依赖于抽象
合成聚合复用 尽量使用合成聚合而不是继承去实现复用
迪米特法则 一个软件实体应该尽可能少的与其它实体发生相互作用
接口隔离 应当为客户提供尽可能小的单独的接口而不应该提供大的综合性的接口
Open Close Principle Software entities like classes, modules and functions should be open for extension but closed for modifications. Template Pattern Strategy Pattern
Single Responsibility Principle A class should have only one reason to change.
Liskov Substitution Principle Derived types must be completely substitutable for their base types
Dependency Inversion Principle High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.
Interface Segregation Principle Clients should not be forced to depend upon interfaces that they don't use.
Law of Demeter(Principle of Least Knowledge) Only talk to your immediate friends

4.The 23 Gang of Four Design Patterns (Cheat Sheet)

委托”是一种极端形式的对象组合,可以始终用于替换继承。委托涉及两个对象:“发件人”将自己传递给“委托人”,让委托人引用发件
监听者模式
并发模式
线程池模式

1 Singleton

Ensure a class only has one instance, and provide a global point of access to it.

单例模式

    public class SimpleSingleton {
    private static SimpleSingleton instance;
    private SimpleSingleton(){}
    public static SimpleSingleton getInstance(){
        if(instance == null)
            instance = new SimpleSingleton();
        return instance;
    }
}
使用懒加载模式,在多线程中可能会创建多个实例
把getInstance()设置为synchronized,不高效,只能有一个线程可以调用该方法,其余的会排队等待
只同步代码块(双重检验锁)  可能未完全初始化  重排序
使用静态内部类比较好    
2 Prototype

Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

clone 复制

3 Factory Method

Define an interface for creating an object, but let the subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

4 Abstract Factory

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

工厂模式(简单工厂方法 工厂方法/静态工厂方法 抽象工厂) Collection Iterator iterator()

        //自己动手  需要时自己new一个对象
        //不使用设计模式  晚餐  米饭 面条 水饺
        Dinner dinnerSelf = new Noodle();
        System.out.println(dinnerSelf);

        //保姆动手(类似小作坊 什么都能自己动手做)
        //简单工厂方法设计模式
        Dinner dinnerSimple = new SimpleFactory().getDinner("noodle");
        System.out.println(dinnerSimple);
        Dinner dinnerAbstract = new DinnerFactory().getNoodle();
        System.out.println(dinnerAbstract);

        //黄焖鸡米饭饭馆 东北饺子店 兰州拉面  饭店(专门的工厂 专业做一种产品)
        //工厂方法设计模式   接口      
        
        Dinner dinnerMehod = new NoodleFactory().getDinner();
        System.out.println(dinnerMehod);        
        //美团外卖  外卖平台(大型百货 什么都能买到并且都是专门工厂提供的 )
        //抽象工厂设计模式  不仅卖饭,卖食材,送饭,等等一些列  families
        //手机工厂 小米 华为 oppo 不仅生产手机 生产手机配件  电池 耳机 等等
        
        //抽象产品可是是一个或多个,从而构成一个或多个产品族 (手机族 电池族 耳机族)
        //在只有一个产品族的情况下,抽象工厂模式实际上退化到工厂方法模式
                
5 Builder

Separate the construction of a complex object from its representation so that the same construction processes can create different representations.

//具体生成器
public class DateBuilder2 implements IDateBuilder{
    private MyDate myDate;
    public DateBuilder2(MyDate myDate){
        this.myDate = myDate;
    }
    @Override
    public IDateBuilder buildDate(int y, int m, int d) {
        myDate.date = y+" "+m+" "+d;
        return this;
    }
    @Override
    public String date() {
        return myDate.date;
    }
}

public class TestUse {
    public static void main(String args[]){
        MyDate date = new MyDate();
        IDateBuilder builder;
        builder = new DateBuilder1(date).buildDate(2066, 3, 5).buildDate(2066, 3, 6);
        System.out.println(builder.date());
        builder = new DateBuilder2(date).buildDate(2066, 3, 5).buildDate(2066, 3, 6);
        System.out.println(builder.date());
    }
}
//指挥者
public class Derector {
    private IDateBuilder builder;
    public Derector(IDateBuilder builder){
        this.builder = builder;
    }
    public String getDate(int y,int m,int d){
        builder.buildDate(y, m, d);
        return builder.date();
    }
}

//生成器模式将对象的构造过程与创建该对象解耦,使对象的创建更加灵活有弹性
//当增加新的具体的生产器时,不必修改指挥者的代码,满足开-闭原则
6 Proxy

Provide a surrogate or placeholder for another object to control access to it.

7 Adapter

Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatibility interfaces.

//对象适配器
public class ObjectAdapter implements Target{
    private Adaptee adaptee;
    public ObjectAdapter(){
        super();
        adaptee = new Adaptee();
    }
    @Override
    public void playFlac(Object src) {
        //可能需要对src作处理
        adaptee.playMp3(src);
    }
}

public class TestUse {
    public static void main(String args[]){
        BookAdapter books = new BookAdapter();
        books.add("think in java");
        books.add("c++ primer");
        books.add("伊索寓言");
        Iterator<String> iterator = books.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}
//适配器
public class BookAdapter extends Book implements Iterable<String>{
    @Override
    public Iterator<String> iterator() {
        return new IteratorAdapter(getEnum());
    }
}
//适配器,目标就是Iterator,被适配者是Enumeration
public class IteratorAdapter implements Iterator<String> {
    Enumeration<String> myEnum;
    public IteratorAdapter(Enumeration<String> myEnum){
        this.myEnum = myEnum;
    }
    @Override
    public boolean hasNext() {
        return myEnum.hasMoreElements();
    }
    @Override
    public String next() {
        return myEnum.nextElement();
    }
}
8 Decorator

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

装饰模式使用被装饰类的一个子类的实例,把客户端的调用委派到被装饰类,装饰模式的关键在于这种扩展是完全透明的。装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为。
使用了装饰器的对象,功能已经增强了,而且可以使用多个装饰器
java.io
9 Composite

Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

10 Facade

Provide a unified interface to a set of interfaces in a system. Façade defines a higher-level interface that makes the subsystem easier to use.

11 Bridge

Decouple an abstraction from its implementation so that the two can vary independently.

桥接模式中有4种角色:

    抽象
    细化抽象
    实现者
    具体实现者
    JDBC is a typical application of Bridge Pattern
12 Flyweight

Use sharing to support large numbers of fine-grained objects efficiently. A flyweight is a shared object that can be used in multiple contexts simultaneously. The flyweight acts as an independent object in each context; it’s indistinguishable from an instance of the object that’s not shared.

 享元模式包括三种角色:

    享元接口(Plyweight):定义了对外公开的获取其内部数据和接收外部数据的方法。
    具体享元(Concrete Plyweight):享元接口的实现。
    享元工厂(Plyweight Factory):该类的实例负责创建和管理享元对象,用户或其他对象必须请求他以获取一个享元对象。
//享元工厂
class FlyweightFactory{
    HashMap<String, IFlyweight> flyweights = new HashMap<String, IFlyweight>();
    IFlyweight getFlyweight(String value){
        IFlyweight flyweight = flyweights.get(value);
        if(flyweight == null){
            flyweight = new Flyweight(value);
            flyweights.put(value, flyweight);
        }
        return flyweight;
    }
    public int size(){
        return flyweights.size();
    }
}
13 Strategy

Defines a family of algorithms, encapsulates each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients who use it.

策略模式中包括三种角色:

策略(Strategy):一个接口,定义了若干个算法(抽象方法)。
具体策略(ConcreteStrategy):策略的实现。
上下文/环境(Context):依赖于策略接口的类。
策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。
public class TestUse {
    public static void main(String args[]){
        Object data = "数据";
        ISaveData saveData = new SaveToRedis();
        SaveClient client = new SaveClient(saveData);
        client.save(data);
        client.setSaveData(new SaveToFile());
        client.save(data);
    }
}
14 Template

Define a skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithms structure.

15 Observer

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

观察者模式中的数据有推和拉的区别
推的方式会将主题更改的内容全部直接推给客户端
拉的方式就是主题的数据更新后,不直接将数据推给客户端,
而是先推送一个通知并提供对应的方法供客户端拉取数据  //给客户端推送一个标志
16 Chain of Responsibility

Avoid coupling the sender of a request to its receiver by giving more then one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

//第三个具体处理者,处理>=0但小于10的
public class Handler3 implements Handler {
    private Handler next;
    @Override
    public int handleRequest(int n) {
        if(n<=Integer.MAX_VALUE) return n;
        else{
            if(next==null)
                throw new NullPointerException("next 不能为空");
            return next.handleRequest(n);
        }
    }
    @Override
    public void setNextHandler(Handler next) {
        this.next = next;
    }
}
//过滤器(Filter)  Log4j记录日志,配置级别
17 Iterator

Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

主要的角色是集合、具体集合、迭代器、具体迭代器
18 Command

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

public class TestUse {
    public static void main(String args[]) throws Exception{
        //接收者
        MakeFile makeFile = new MakeFile();
        //命令
        CommandCreate create = new CommandCreate(makeFile);
        CommandDelete delete = new CommandDelete(makeFile);
        //请求者
        Client client = new Client();
        //执行命令
        client.setCommand(create).executeCommand("d://test1.txt");
        client.setCommand(create).executeCommand("d://test2.txt");
        client.setCommand(delete).executeCommand("d://test2.txt");
    }
}//执行完后在D盘会有一个test1.txt的文件,test2.txt本页创建了,又被删除

19 Mediator

Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and lets you vary their interaction independently.

//具体同事
public class PersistentDB implements IPersistent{
    private Object data;
    @Override
    public void getData(Object data, Midiator midiator) {
        getData(data);
        midiator.notifyOther(this, data);
    }
    @Override
    public void saveData() {
        System.out.println(data + " 已保存到数据库");
    }
    @Override
    public void getData(Object data) {
        this.data = data;
        saveData();
    }
}

//具体中介者
public class Midiator {
    PersistentDB persistentDB;//此处可以使用List来存放所有的同事
    PersistentFile persistentFile;
    public Midiator setPersistentDB(PersistentDB persistentDB) {
        this.persistentDB = persistentDB;
        return this;
    }
    public Midiator setPersistentFile(PersistentFile persistentFile) {
        this.persistentFile = persistentFile;
        return this;
    }
    public void notifyOther(IPersistent persistent,Object data){
        if(persistent instanceof PersistentDB)//如果同事都放在List中,此处遍历即可
            persistentFile.getData(data);
        if(persistent instanceof PersistentFile)
            persistentDB.getData(data);
    }
}
public class TestUse {
    public static void main(String args[]){
        Object data = "数据";
        PersistentDB persistentDB = new PersistentDB();
        PersistentFile persistentFile = new PersistentFile();
        Midiator midiator = new Midiator();
        midiator.setPersistentDB(persistentDB).setPersistentFile(persistentFile);
        persistentDB.getData(data, midiator);
        persistentFile.getData(data, midiator);
    }
}//输出(省略了换行符):数据 已保存到数据库数据 已保存到文件数据 已保存到文件数据 已保存到数据库


20 State

Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

//具体状态
public enum SaveSmallData implements ISaveData{
    instance;
    @Override
    public void save(Object data) {
        System.out.println("保存到Redis:" + data);
    }
}

public class TestUse {
    public static void main(String args[]){
        String smallData = "小数据";
        String middleData = "介于小数据和大数据之间的数据";
        String bifgData = "这里就假定这是一个很大很大很大的数据";
        SaveDataController saveDataController = new SaveDataController();
        saveDataController.save(smallData);
        saveDataController.save(middleData);
        saveDataController.save(bifgData);
    }
}
21 Interpreter

Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

    解释器模式一般包括四种角色:
    抽象表达式:该角色为一个接口,负责定义抽象的解释操作。
    终结符表达式:实现抽象表达式接口的类。
    非终结表达式:也是实现抽象表达式的类。
    上下文(Context):包含解释器之外的一些全局信息。
    
    使用该模式设计程序一般需要三个步骤:
    解析语句中的动作标记。
    将标记规约为动作。
    执行动作。
22 Memento

Without violating encapsulation, capture and externalize an object’s internal state so that the object can be restored to this state later.

备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式。 备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。
三种角色:备忘录(Memento)角色     发起人(Originator)角色   负责人(Caretaker)角色
//简单的备忘录模式
public class SimpleMemento {
    public static void main(String[] args) throws Exception {
        Originator originator = new Originator();//发起人,要被保存的对象,是他创建要保存的信息
        Caretaker caretaker = new Caretaker();   //辅助保存的对象
        originator.setState("stateOne");    //设置状态
        caretaker.saveMemento(originator.createMemento());      //保存状态
        originator.setState("stateTwo");    //修改状态
        originator.recoverMemento(caretaker.recoverMemento());  //恢复状态
    }
}
23 Visitor

Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

访问者模式可以在Visitor类中集中定义一些关于集合中对象的操作
动态双重分派也算是完成了(通过调用一个其它对象的方法,传入自己,在其他类的这个方法中再通过传入的这个参数调用自己
//VIP用户,具体元素
public class UserVIP implements User{
    String estimation;
    public UserVIP(String estimation){
        this.estimation = estimation;
    }
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    String getEstimation(){
        return estimation;
    }
}

//具体访问者
public class APPOwner implements Visitor{
    @Override
    public void visit(UserVIP user) {
        String estimation = user.getEstimation();
        if(estimation.length()>5)
            System.out.println("记录一条有效反馈:" + estimation);
    }
    @Override
    public void visit(UserOrdinary user) {
        String estimation = user.getEstimation();
        if(estimation.length()>10)
            System.out.println("记录一条有效反馈:" + estimation);
    }
}

5 参考文献

  1. The 23 Gang of Three Design Patterns
  2. Gang Of Four (GoF) Design Patterns
  3. Design Patterns in Java Tutorial
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi阅读 7,332评论 0 10
  • **2014真题Directions:Read the following text. Choose the be...
    又是夜半惊坐起阅读 9,505评论 0 23
  • 之前会认为有的人是你一生的挚友,后来才发现她给你的伤比给你的糖多,多到你自己无法治愈,凝结成痕。也许她就是你...
    不开花的仙人掌上雨初晴阅读 78评论 0 0
  • 真的不敢相信一年,就这样结束了,大概我对于一年的概念,不是在热热闹闹的除夕之夜,听着春节联欢晚会所谓的倒计时,才意...
    酒笙清梅阅读 465评论 5 3
  • 今年九月的天有些微微凉,秋风似乎比以往来得要更早一些。 今天坐车路过你们学校,本想和以往一样在群里发个定位,后...
    半分微光阅读 526评论 0 4