不懂设计模式终究是下层

2017-09-22  本文已影响31人  像鸟一样飞
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需要具备两个条件

模板方法模式(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. 一般与工厂方法模式,模板方法模式混合使用情况较多。
上一篇下一篇

猜你喜欢

热点阅读