首页 > java > basic > 20.Java设计模式

20.Java设计模式

软件设计领域的四位世界级大师Gang Of Four (GoF):Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides合著了一本非常著名的书《Design Patterns - Elements of Reusable Object-Oriented Software》翻译的中文名为《设计模式:可复用面向对象软件的基础》.书中提出了23种基本设计模式,从理论高度提炼并规范了设计模式,对面向对象软件设计产生了巨大影响.

图19-1

1 设计模式简介

总体来说设计模式分为三大类:

  • 创建型模式,共五种:工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式.
  • 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式.
  • 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式.

有些设计模式我个人认为,不是很具象,就像星座一样抽象概念居多,导致应用场景不明确. 所以不希望他们占用我过多的脑容量和时间.只挑选几个含金量高,模型具象,应用场景广泛的模式来介绍. 以下这几个都是非常值得花时间去熟悉的模式.

2 单例模式

单例模式即是只产生一个对象的模式.在Java中,每次使用new关键字,就会产生一个新的Java对象. 有时我们需要只有一个对象产生,比如一些管理类,全局管理其它模块时,这个管理类适合采用单例模式.

普通的单例模式分为2种,懒汉式和饿汉式.懒汉式比较懒,用到的时候才创建对象,饿汉式不讲理,你用不用我都创建好放着.

降龙十八掌秘籍

普通单例模式的秘籍:

  • 将构造函数定义为私有private,只能在本类中创建,不能被继承.
  • 通过private和static关键字定义一个私有并且静态的本类实例对象,保证内存中只有1个实例,并且只有本类能调用.
  • 公开一个获得本类实例的静态方法,来获取这个实例,保证每次得到的实例都是同一个,来实现单例模式.

列出4种常用的单例模式的写法,推荐第4种. 第4种是通过内部类实现,高效且线程安全. 记住这个好了,其他的可以忘.

2.1 懒汉式单例模式

懒汉式单例模式代码:

/**
 * 懒汉式单例模式
 */
class Singleton1 {

    private static Singleton1 singleton1;

    private Singleton1() {

    }

    public static Singleton1 getInstance() {
        if (null == singleton1) {
            singleton1 = new Singleton1();
        }
        return singleton1;
    }
}

2.2 饿汉式单例模式

饿汉式单例模式代码:

/**
 * 饿汉式单例模式
 */
class Singleton2 {

    private static Singleton2 singleton2 = new Singleton2();

    private Singleton2() {
    }

    public static Singleton2 getInstance() {
        return singleton2;
    }
}

2.3 线程安全的懒汉式

线程安全的懒汉式代码:

/**
 * 线程安全懒汉式单例模式
 */
class Singleton3 {

    private static Singleton3 singleton3;

    private Singleton3() {

    }

    public static synchronized Singleton3 getInstance() {
        if (null == singleton3) {
            singleton3 = new Singleton3();
        }
        return singleton3;
    }
}

2.4 内部类线程安全单例模式

这种方式利用java的final关键字特性,一旦赋值无法改变.线程安全,效率高,推荐方式.java内部类线程安全单例模式示例代码:

/**
 * 内部类线程安全单例模式
 */
class Singleton4 {

    private static class SingletonHolder {
        public final static Singleton4 instance = new Singleton4();
    }

    public static Singleton4 getInstance() {
        return SingletonHolder.instance;
    }
}

3 工厂模式

工厂模式本质是通过条件语句,根据不同的条件创建不同的对象.通常情况下,产生的对象继承自同一个父类,工厂类提供的方法返回的类型为父类对象类型.达到对象封装的作用.

java工厂模式代码示例:

package com.dashidan.lesson19;

/**
 * 大屎蛋教程网-dashidan.com
 * <p>
 * Java教程基础篇:  19.Java设计模式
 * 工厂模式
 */
public class Demo2 {
    public static void main(String[] args) {
        /** 传入需要生产的产品类型*/
        Product product = Factory.getProduct(1);
        /** 打印产品信息*/
        product.info();
    }
}

/**
 * 工厂模式
 * 根据不同的类型,生产不同的产品
 */
class Factory {
    public static Product getProduct(int type) {
        switch (type) {
            case 1:
                return new Product1();
            case 2:
                return new Product2();
        }
        return null;
    }
}

/**
 * 产品的父类是抽象类,提供一个info方法
 */
abstract class Product {

    public abstract void info();
}

/**
 * 产品Product1继承自父类Product
 */
class Product1 extends Product {
    @Override
    public void info() {
        System.out.println("Product1 info.");
    }
}

/**
 * 产品Product2继承自父类Product
 */
class Product2 extends Product {
    @Override
    public void info() {
        System.out.println("Product2 info.");
    }
}

输出:

Product1 info.

4 观察者模式

观察者模式(也称为发布(publish)-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式).是一个非常棒的降低代码耦合度的方式.

降龙十八掌秘籍

观察者模式的秘籍:

  • 观察者在发布者对象上注册消息侦听,加入消息侦听列表
  • 发布者遍历消息侦听列表,调用观察者方法处理消息
  • 不同的观察者对象通常继承同一个观察者接口,通过接口方法统一处理

通常用在一对多或者多对多的场景中,一个对象数据变化了,需要通知其他对象的场景. 比如ActionScript3语言底层的事件冒泡机制,就是采用观察者模式设计.

观察者模式代码示例:

package com.dashidan.lesson19;


import java.util.ArrayList;

/**
 * 大屎蛋教程网-dashidan.com
 * <p>
 * Java教程基础篇:  19.Java设计模式
 * 观察者模式
 */
public class Demo3 {
    public static void main(String[] args) {
        /** 初始化发布者和观察者*/
        Publisher publisher = new Publisher();
        Observer1 observer1 = new Observer1();
        Observer2 observer2 = new Observer2();
        /** 加入2个观察者到发布者的消息侦听队列*/
        publisher.addObserver(observer1);
        publisher.addObserver(observer2);
        /** 通知观察者*/
        publisher.notifyAllObserver();
    }
}

/**
 * 发布者
 */
class Publisher {

    /**
     * 发布者的消息侦听队列
     */
    ArrayList<IObserver> observers = new ArrayList<>();

    /**
     * 加入消息侦听队列
     */
    public void addObserver(IObserver iObserver) {
        System.out.println("加入观察者");
        observers.add(iObserver);
    }

    /**
     * 通知侦听队列中所有的观察者
     */
    public void notifyAllObserver() {
        for (IObserver iObserver : observers) {
            System.out.println("通知观察者");
            iObserver.action();
        }
    }
}

/**
 * 观察者接口
 */
interface IObserver {
    void action();
}

/**
 * 观察者Observer1类
 */
class Observer1 implements IObserver {
    @Override
    public void action() {
        System.out.println("Observer1 action.");
    }
}

/**
 * 观察者Observer2类
 */
class Observer2 implements IObserver {
    @Override
    public void action() {
        System.out.println("Observer2 action.");
    }
}

输出:

加入观察者
加入观察者
通知观察者
Observer1 action.
通知观察者
Observer2 action.
转载请保留原文链接.