不懂设计模式终究是下层

sjms.jpg

单例模式

概念:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例
UML中带==下划线的属性==是静态的;
如下特点:

  1. 构造方法私有
  2. 指向自己实例的私有静态引用
  3. 以自己实例为返回值的公有静态方法
    单例模式可详细分为两类, 饿单例模式,懒单例模式
/**
 * 饿汉式单例模式,在类被加载的时候就实例化好了对象
 */
public class SingleTon {
    public static SingleTon singleTon = new SingleTon();

    private SingleTon() {
    }

    public static SingleTon getSingleTon() {
        return singleTon;
    }
}
/**
 * 懒汉式单例模式,在调用实例化方法的时候才会创建它的实例
 */
public class SingleTon {
    public static SingleTon singleTon;

    private SingleTon() {
    }

    public static synchronized SingleTon getSingleTon() {
        if (singleTon == null) {
            singleTon = new SingleTon();
        }
        return singleTon;
    }

}

单例模式的优点:

  1. 在内存中只有一个对象,节省内存空间
  2. 避免频繁的创建销毁对象,加快效率
  3. 避免对共享资源的多重占用
  4. 可以全局访问
    适用场景:
  5. 只能适用单例类提供的方法来获取单例对象,使用反射会创建新的对象
  6. 多线程使用单例模式时,要注意线程安全
  7. 不要做断开单例类对象与类中静态引用的危险操作。(╯°Д°)╯︵┻━┻

在java中饿汉要优于懒汉,还要因为构造方法是私有的,所以不能被继承ε(┬┬﹏┬┬)3

工厂方法模式

概念:定义一个创建对象的接口,让子类决定实例化哪一个类,工厂方法模式使一个类的实例化延迟到了子类。

interface IProduct {
    public void productMethod();
}

class Product implements IProduct {

    @Override
    public void productMethod() {
        System.out.println("产品");
    }
}

interface IFactory {
    public IProduct createProduct();
}

class Factory implements IFactory {

    @Override
    public IProduct createProduct() {
        return new Product();
    }
}

public class FactoryClient {

    public static void main(String[] arg) {
        IFactory factory = new Factory();
        IProduct product = factory.createProduct();
        product.productMethod();
    }

}

工厂模式根据抽象程度分为三种:简单工厂模式(静态工厂模式),工厂方法模式,抽象工厂模式。
主要优点:

  1. 使代码结构清晰,有效的封装变化。在编程中有些产品的实例化是比较复杂的多变的,通过工厂模式,将产品的实例化过程封装起来,使用者不用管产品的实例化过程,只需要依赖工厂即可得到产品对象。
  2. 调用者屏蔽了具体的产品类,即使产品的实现发生了变化,调用只关心或者依赖产品的接口就好了,不会产生任何影响。
  3. 降低耦合度,产品的实例化通常是比较复杂的,需要依赖很多的类,而这些类对于调用者来说无需知道,工厂只是把最终的产品对象,交给调用者,产品所依赖的类都是不存在的ヾ(๑╹◡╹)ノ"

通过工厂方法模式的类图可以看出,工厂模式有四个要素:

  1. 工厂接口,是工厂方法模式的核心,用于与调用者交互,用来提供产品。
  2. 工厂实现,决定如何实现产品,有多少种产品,就要有多少种工厂实现。
  3. 产品接口,所有产品都必须遵守产品接口所定义的规范,产品接口也是调用者最关心的,产品接口定义的好坏,决定了代码的稳定性,与工厂接口一样,可以用抽象类来代替,但是不能违反里氏替换原则ヽ(#`Д´)ノ┌┛〃
  4. 产品实现,决定了产品的在客户端的具体行为。

适用场景:
作为“创建类模式”,在任何需要生成复杂对象的地方,都可以使用工厂模式。
如果创建一个类需要大量的依赖其他类,那么调用者就会产生很强的耦合度,这时候可以考虑使用工厂模式,来降低调用者与外界的耦合度。

抽象工厂模式

建造者模式

定义:将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。
类型:创建类模式
四个要素:

  1. 产品类,一般是一个创建过程较为复杂的对象,在实际编程中,产品类可以是一个抽象类,或多个抽象类及其实现子类组成;
  2. 抽象建造者,为了将具体的建造过程交于他的子类实现,更容易扩展,最少有两个方法,一个是建造产品,一个是返回产品。
  3. 建造者,实现抽象建造者的方法,组建产品,返回组建好的产品。
  4. 导演类,调用适当的建造者来组建产品,一般不与产品发生依赖,用于封装程序中易变的部分(メ`ロ´)/
class Product {
    private String name;
    private String type;

    public void setName(String name) {
        this.name = name;
    }

    public void setType(String type) {
        this.type = type;
    }

    public void showProduct() {
        System.out.println("name = " + name);
        System.out.println("type = " + type);
    }
}

abstract class Builder {
    public abstract void setPart(String arg1, String arg2);
    public abstract Product getProduct();
}

class ConcreteBuilder extends Builder {
    private Product product = new Product();

    @Override
    public void setPart(String arg1, String arg2) {
        product.setName(arg1);
        product.setType(arg2);
    }

    @Override
    public Product getProduct() {
        return product;
    }
}

/**
 * 导演让你创建啥,你就创建啥ヾ(o・ω・)ノ
 */
class Director {
    private Builder builder = new ConcreteBuilder();

    public Product getAProduct() {
        builder.setPart("保时捷", "卡宴");
        return builder.getProduct();
    }

    public Product getBProduct() {
        builder.setPart("凤凰牌", "自行车");
        return builder.getProduct();
    }
}

public class BuilderClient {
    public static void main(String[] args) {
        Director director = new Director();
        Product p1 = director.getAProduct();
        p1.showProduct();
        Product p2 = director.getBProduct();
        p2.showProduct();
    }

}

建造者模式的优点:

  1. 一般产品类和建造者类都是比价稳定的,因此,将主要逻辑,以及具体实现,这些易变的部分封装在了导演类中。
  2. 当有现需求时候,只要实现一个新的建造者类就可以不动之前经过测试的代码了,不会引入风险。
    建造者模式与工厂模式的区别:
    与工厂模式相比,建造模式一般用来创建更加复杂的对象, 因为更加复杂的对象创建过程,需要一个导演类将这个复杂的创建过程独立出来。也就是说工厂模式将所有的对象创建过程封装在工厂中,有工厂类想客户端提供最终的产品。而建造者模式中,建造者只提供产品的各个组件的建造,然后将具体的建造过程交给导演类,由导演类将各个组件的建造特定的规则组成产品,交给客户端。

原型模式(Prototype)

定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
类型:创建类模式
原型模式主要用于对象的复制,它的核心就是原型类prototype,prototype需要具备两个条件

  • 实现Cloneable接口,它的作用只有一个,就是通知虚拟机可以安全的在实现了此接口的类上使用clone方法。只有实现了这个接口的类才可以被clone。
  • 重写clone方法,将权限修饰符修改为public,

模板方法模式(template)

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

架构师将整个应用的大体逻辑,试用大量的接口或者抽象类讲真个系统串起来,然后根据实现的难度不同交给高级工程师,初级工程师,由他们来实现子类,完成开发。
模板方法模式的结构:

模板方法模式由一个抽象类和一组(n>=1)子类组成,抽象类中方法分为三种

  1. 抽象方法,父类只声明而不实现,定义好规范,然后由其子类去实现。
  2. 模板方法,由抽象类声明并加以实现,一般来说模板方法调用抽象方法来完成主要的逻辑功能,并且,模板方法大多数会定义成final类型,指明主要的逻辑在子类中无法被重写。
  3. 钩子方法,由抽象类声明并加以实现,但是子类可以去扩展,子类可以通过扩展钩子方法,来影响模板方法的逻辑。
  4. 抽象类的任务是搭建逻辑框架,通常由经验丰富的人,抽象类的好坏直接决定了程序是否稳定,
  5. 实现类用来实现细节,模板方法正式通过实现类中扩展的方法来完成逻辑,只要实现类中扩展方法通过了单元测试,在模板方法正确的前提下,一般整体不会出现太大的错误。

适用场景:

  • 容易扩展,一般来说,抽象类中的模板方法是不易发生改变的部分,而抽象方法式容易发生改变的部分,因此通过增加实现类一般很容易实现功能的扩展,符合开闭原则。
  • 便于维护,对于模板方法模式来说,正是由于他们的主要逻辑相同,才使用模板方法。
  • 灵活,因为有钩子方法,因此子类的实现也可以影响父类的主要运行逻辑,但是却违反了里氏替换原则。
  • 多个子类拥有相同的方法,并且这些方法的逻辑相同的情况下可以使用模板方法模式,在程序的主框架相同,细节不同的情况下,比较适合使用这种模式。

中介者模式

定义:用一个中介者对象封装一些列的交互对象,中介者使个对象不需要显示的互相作用,从而降低耦合,而且可以独立的改变他们之间的交互。
结构:中介者模式又称为调停者模式,氛围三部分

  1. 抽象中介者,定义好同事类对象到中介者对象的接口,用于各同事类之间的通讯,一般包括一个或者多个抽象的时间方法,并由子类去实现。
  2. 中介者实现类:从抽象中介者继承而来,实现抽象中介者中定义的事件方法。从一个同事类接收消息,然后通过消息影响其他同时类。
  3. 如果一个对象会影响其他的对象,同时也会被其他对象影响,那么这两个对象称为同事类。在类图中,同事类只有一个,这其实是现实的省略,在实际应用中,同事类一般由多个组成,他们之间相互影响,相互依赖。同事类越多,关系越复杂。并且,同事类也可以表现为继承了同一个抽象类的一组实现组成。在中介者模式中,同事类之间必须通过中介者才能进行消息传递。

代理模式

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

结构:

  1. Subject抽象主题角色,可以是抽象类也可以是一个接口,普通业务类型的定义,无特殊要求。
  2. RealSubject具体角色,被委托角色,业务逻辑具体执行者。
  3. Proxy代理角色,负责对真实角色的应用,把所有抽象主题的方法,委托给真是主题角色实现,并且在真实角色处理完毕前后座预处理和善后工作。

模板代码:

interface Subject {
    void request();
}

class RealSubject implements Subject {
    private String name;

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

    @Override
    public void request() {
        System.out.println("name = " + name);
    }
}

class Proxy implements Subject {
    private Subject subject = null;

    public Proxy(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void request() {
        this.before();
        this.subject.request();
        this.after();
    }

    //预处理工作
    private void before() {
        System.out.println(System.currentTimeMillis() + "预处理工作");
    }

    //善后工作
    private void after() {
        System.out.println(System.currentTimeMillis() + "善后工作");
    }
}

public class ClientProxy {
    public static void main(String[] args) {
        Subject subject = new RealSubject("zhangsan");
        Subject proxy = new Proxy(subject);
        proxy.request();
    }
}
1506480477076预处理工作
name = zhangsan
1506480477076善后工作

代理模式优点:

  1. 职责清晰,真是角色就是实现实际的业务逻辑,不用关心其他非本职事物,
  2. 高扩展性,具体主题角色可以随时改变,只要实现了接口,甭管怎么变化,都逃不出我的手心,代理类可以不改变的情况下使用。
  3. 智能化,︵╰(‵□′)╯︵┻━┻

观察者模式

定义:定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象,都会的到通知并自动更新。

observe

在软件系统中通常会有这样的需求,如果一个对象的状态发生改变,某些与他先关的对象也要做出改变。

结构:

  1. 被观察者,从类图中可以看到,类中有一个用来存放观察者对象的Vector的容器,(在多线程中Vector是线程安全的,而不是用list),这个集合是被观察者的核心,另外有三个方法,attach方法,向这个容器中添加观察者对象,detach方法,从容器中移除观察者对象,notify方法,依次调用观察对象的对应方法。这个角色可以是是接口,也可以是抽象类或者具体的类,因为很多情况是和其他模式一起使用。
  2. 观察者,观察者角色一般是一个接口,它只有一个update方法,在被观察者状态发生改变是,这个方法就会被触发调用。
  3. 具体的被观察者,使用这个角色是为了便于扩展,可以在此角色中定义具体的业务逻辑。
  4. 具体的观察者,定义被观察者状态发生改变时,回调的观察者对象具体处理的逻辑。
/**
 * 被观察者
 */
abstract class Observeable {
    private Vector<Observer> vector = new Vector();

    public void addObserve(Observer obs) {
        this.vector.add(obs);
    }

    public void removeObserve(Observer obs) {
        this.vector.remove(obs);
    }

    protected void notifyObserve() {
        for (Observer observer : vector) {
            observer.update();
        }
    }

    public abstract void doSomething();
}

/**
 * 被观察者实例
 */
class ContractObserve extends Observeable {

    @Override
    public void doSomething() {
        System.out.println("被观察者事件发生");
        this.notifyObserve();
    }
}

interface Observer {
    void update();
}

/**
 * 实例观察者1
 */
class ConcreteObserve1 implements Observer {

    @Override
    public void update() {
        System.out.println("观察者1收到信息,并进行处理");
    }
}

/**
 * 实例观察者2
 */
class ConcreteObserve2 implements Observer {

    @Override
    public void update() {
        System.out.println("观察者2收到信息,并进行处理");
    }
}

public class ObserveClient {

    public static void main(String[] args) {
        //创建被观察者
        //这里真正new的都是实现子类
        Observeable obs = new ContractObserve();
        obs.addObserve(new ConcreteObserve1());
        obs.addObserve(new ConcreteObserve2());
        obs.doSomething();
    }
}

观察者模式的优点:
观察者与被观察者之间是一种轻度的关联关系,并且是抽象耦合的,这样对于二者来说都比较容易扩展。观察者模式是一种常用的触发机制,它形成一条触发链,依次对各个观察者的方法进行处理,但同时由于是链式触发,所以当观察者较多的时候,性能是比较担忧的,

责任链模式

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

策略模式

定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以相互转换。
策略模式是把算法封装到一系列的类中去,并且这些类实现相同的接口,相互之间可以相互替换。他与模板方法的区别在于,在模板方法模式中调用算法的主体在抽象的父类中,而在策略模式中,调用算法的主体则是在封装了Context的封装类中。

结构:

  1. 封装类,也叫上下文,对策略进行二次封装,目的是避免高层模块对策略的直接调用。
  2. 抽象策略,通常情况下为一个接口,当各个类中出现重复的逻辑时候,使用抽象类来封装这部分代码,此时会看上去像是模板方法。
  3. 具体策略,具体策略通常由一组封装了算法的类来担任,这些类之间可以根据需要自由替换。

策略模式的优点

  1. 策略类之间可以相互转换,由于策略类实现自统一个抽象,所以他们之间可以自由切换。
  2. 易于扩展,增加一个新的策略模式非常的简单,可以在不修改原有代码的基础上进行扩展。
  3. 避免使用多重条件,如果不使用策略模式,所有的算法需要用条件语句去进行连接,这样的做法非常不容易维护。
  4. 维护各个策略类给开发者带来额外的开销。
  5. 客户端必须要知道所有策略类的区别,然后决定用哪一个,但是有违背迪米特法则。
    ヽ(`Д´)ノ︵ ┻━┻

适用场景:
策略模式实际上就是面向对象中的继承和多态。

  1. 几个类的主要逻辑相同,只是部分逻辑和算法上有所区别的情况。
  2. 有相似的行为,或者算法,客户端需要动态的取决定使用哪一个,那么可以使用策略模式,将这些算法封装起来供客户端调用。
  3. 一般与工厂方法模式,模板方法模式混合使用情况较多。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容

  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,933评论 1 15
  • 设计模式基本原则 开放-封闭原则(OCP),是说软件实体(类、模块、函数等等)应该可以拓展,但是不可修改。开-闭原...
    西山薄凉阅读 3,784评论 3 14
  • 创建型模式 抽象工厂模式(abstract facroty) 3.1模式动机 在工厂方法模式中具体工厂负责生产具体...
    僚机KK阅读 734评论 0 2
  • 一、设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者...
    RamboLI阅读 749评论 0 1
  • 接触前端两三个月的时候,那时候只是听说设计模式很重要,然后我就去读了一本设计模式的书,读了一部分,也不知道这些设计...
    艰苦奋斗的侯小憨阅读 3,043评论 2 39