常用设计模式

工厂设计模式

  • 工厂设计模式,主要用于进行实例化对象时的解耦操作,避免使用new关键字实例化对象,通过反射,根据类名称动态创建对象
  • 示例:
package design;
/**
   *静态工厂模式
   */
public class Factory {
/**
   *构造方法私有化
   */
private Factory (){

 }
/**
   * 获取指定类名称的对象
   * @param className    * @param <T>
   * @return T
   */
public static <T> T getInstance(String className){
        T object =null;
        try {
            object = (T) Class.forName(className).newInstance();
        }catch (Exception e){
            e.printStackTrace();
        }
        return object;
    }
}

动态代理模式

  • 动态代理模式,主要用于对同一接口子类的相同逻辑进行代理操作
  • 示例:
package design;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
   * 动态代理模式
   */
public class DynamicProxy implements InvocationHandler {
    private Object target;
    /**
     * 代理的目标对象
     * @param target
     * @return
     */
    public Object proxy(Object target){
        this.target=target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }
    /**
     * 目标方法执行前执行
     * @param object
     */
    public void before(Object object){
        System.out.println("目标方法执行前执行");
    }
    /**
     * 目标方法执行后执行
     * @param object
     */
    public void after(Object object){
        System.out.println("目标方法执行后执行");
    }
    /**
     * Processes a method invocation on a proxy instance and returns
     * the result.  This method will be invoked on an invocation handler
     * when a method is invoked on a proxy instance that it is
     * associated with.
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        this.before(proxy);
        Object result =method.invoke(proxy,args);
        this.after(result);
        return result;
    }
}

单例模式一

  • 单例模式一:采用static final 修饰在类内部实例化的对象,保证对象的唯一性,此种方式,实在类加载的过程中实例化对象,无论是否使用,都会实例化。
  • 示例
package design;
/**
   * 单例模式一
   */
public class SingletonOne {
    /**
     * 实例化对象唯一
     */
    private static final SingletonOne INSTANCE =new SingletonOne();
    /**
     * 构造方法私有化
     */
    private SingletonOne(){

    }
    /**
     * 获取单例对象
     * @return
     */
    public static SingletonOne getInstance(){
        return INSTANCE;
    }
}

单例模式二

  • 单例模式二:采用volatile关键字修饰实例化对象,并通过同步锁(锁Class)的形式,保证实例化对象的唯一性,此方式在第一次使用时进行实例化
  • volatile关键字修饰的变量与普通变量的读取方式不同
01.png

volatile定义的变量,将直接使用原始数据进行处理,更改后立即生效

  • 示例
package design;
/**
   * 单例模式二
   */
public class SingletonTwo {
    /**
     * 使用volatile关键字修饰单例对象
     * volatile定义的变量,将直接使用原始数据进行处理,更改后立即生效
     */
    public static volatile SingletonTwo instance;
    /**
     * 构造方法私有化
     */
    private SingletonTwo(){

    }
    /**
     * 获取单例对象
     * @return
     */
    public static SingletonTwo getInstance(){
        if(instance ==null){
            //通过同步锁住当前类,来保证线程安全,并提高性能,若直接同步该方法,会大大降低性能
            synchronized (SingletonTwo.class){
                if (instance ==null){
                    instance =new SingletonTwo();
                }
            }
        }
        return instance;
    }
}

中介者模式

(转载自喻红叶《Java与模式-中介者模式》
  • 中介者模式的定义:用一个中介对象来封装一些列的对象交互,中介者使得各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式解决问题的思路很简单,就是通过引入一个中介对象,让其他对象只与中介对象交互,而中介对象知道如何和其他所有对象的交互,这样对象之间的交互关系就没有了,从而实现了对象之间的解耦。由此,我们也可以看出一个问题,那就是中介对象控制着整个系统的逻辑,它会过于复杂,这是一个缺点。中介者模式的本质是封装交互:
    • (1)对象在自身状态发生改变时报告给中介对象;
    • (2)中介对象控制着整个系统的逻辑,它知道如何与所有对象交互;
    • (3)对象需要对中介对象发出的请求作出回应。
  • 中介者模式中的角色:
    • Mediator:中介者接口,定义各个同事之间交互所需要的方法;
    • ConcreteMediator:具体的中介者,它需要了解并维护各个同事对象,并负责具体的协调各同事对象的交互关系;
    • Colleague:所有同事对象的父类,一般实现成抽象类,主要负责约束同事对象的类型,并负责实现一些公共功能;
    • ConcreteMediator:具体的同事类,实现自己的业务,当需要与其他同事对象通信时,就与持有的中介者通信,中介者会负责与其他同事的交互。在标准的中介者模式中,将使用中介者来交互的那些对象叫做同事类,它们继承自相同的父类,所以叫做同事。正是由于它们之间的交互很复杂,所以才产生了把这些交互关系分离出去,让中介者来处理。
  • 示例:
    • 以电脑来看电影为例子,首先光驱从光盘中读取数据,然后通知CPU将数据分离成音频和视频,CPU处理完毕后再分别将数据传送给声卡和显卡进行播放。从上面的描述的中发现,光驱盒CPU是耦合的,CPU又和声卡显卡是耦合的,怎么解耦的呢?如果使用中介者模式,通过引入主板作为中介者,所有的对象都与主板交互,那么播放电影的流程就变成了这样:
      • (1)光驱从光盘读取到数据,通知主板,数据准备好了;
      • (2)主板收到光驱的请求后,将原始数据传给CPU,让它将数据分离成音频和视频;
      • (3)CPU将数据分离后,通知主板,数据分离完毕;
      • (4)主板收到CPU通知后,分别将音频和视频传给声卡和显卡;
      • (5)声卡和显卡同时播放。
        这样一个过程中,所有的类只与主板耦合,而不与其他类保持关系,做到了解耦,而且过程很清晰。实际上计算机硬件就是这样通信的,只不过更复杂一些,所以这些东西都是相通的,重要的是思想。
  • Java实现:
    • 同事对象的父类
package design;
/**
 * 同事对象的父类,一般实现成抽象类,用于约束同事对象的类型
 * 同时实现一些功能公共方法,例如持有中介者对象
 */
public abstract class Colleague {
    //所有的同事对象都需要持有中介对象
    private Mediator mediator;

    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }

    public Mediator getMediator() {
        return mediator;
    }
}
  • 中介者接口
package design;
/**
 * 中介者接口
 */
public interface  Mediator {
    /**
     * 同事对象自身状态改变时,通过这个方法通知中介者对象
     * @param obj
     */
    public void changed(Colleague obj);

    /**
     * 中介者对象需要知道所有同事对象
     * @param instance
     */
    public void setCDDriver(CDDriver instance);
    public void setCPU(CPU instance);
    public void setVideoCard(Video instance);
    public void setSoundCard(Sound instance);
}
  • 光驱类
package design;
/**
 * 光驱类,负责从光盘中读取数据
 */
class CDDriver extends Colleague {
    //从光盘读取的原始数据
    private String originData;

    public CDDriver(Mediator mediator) {
        super(mediator);
    }
    public String getOriginData() {
        return originData;
    }

    /**
     * 读取光盘数据,一旦读取到数据,就要通知中介者对象数据已经准备好了
     */
    public void readCD(String originData) {
        this.originData = originData;
        //通知中介对象,自己的状态发生了改变
        getMediator().changed(this);
    }
}
  • CPU类
package design;
/**
 * CPU类,负责将原始数据分离成音频和视频
 */
public class CPU extends Colleague {

    //声音数据
    private String soundData;
    //视频数据
    private String videoData;

    public CPU(Mediator mediator) {
        super(mediator);
    }
    public String getSoundData() {
        return soundData;
    }
    public String getVideoData() {
        return videoData;
    }

    /**
     * 将数据分离,同时通知中介者对象,数据已经分离
     * @param originData
     */
    public void sperateData(String originData) {
        this.soundData = originData.split(",")[1];
        this.videoData = originData.split(",")[0];

        //通知中介对象,自己的状态发生了改变
        getMediator().changed(this);
    }
}
  • 显卡类,播放视频
package design;
/**
 * 显卡类,播放视频
 */
public class Video extends Colleague {

    public Video(Mediator mediator) {
        super(mediator);
    }
    public void showVideo(String videoData) {
        System.out.println("正在观看:" + videoData);
    }
}
  • 声卡类
package design;

/**
 * 声卡类,播放声音
 */
public class Sound extends Colleague {

    public Sound(Mediator mediator) {
        super(mediator);
    }
    public void showSound(String soundData) {
        System.out.println("解说:" + soundData);
    }
}
  • 主板类
package design;
/**
 * 主板类,实现中介者
 */
public class MainBoard implements Mediator {
    private CDDriver cd;
    private CPU cpu;
    private Video vc;
    private Sound sc;

    public void setCDDriver(CDDriver instance) {
        this.cd = instance;
    }
    public void setCPU(CPU instance) {
        this.cpu = instance;
    }
    public void setVideoCard(Video instance) {
        this.vc = instance;
    }
    public void setSoundCard(Sound instance) {
        this.sc = instance;
    }

    /**
     * 当同时对象自身状态发生改变时,调用此方法通知中介者对象
     * 中介者对象在进行逻辑控制,与其他同对象交互
     */
    public void changed(Colleague obj) {
        //如果是光驱类,需要通知CPU去分离数据
        if(obj instanceof CDDriver) {
            String originData = ((CDDriver) obj).getOriginData();
            this.cpu.sperateData(originData);
        }else if(obj instanceof CPU){//如果是CPU类,需要通知声卡和显卡去播放
            String videoData = ((CPU) obj).getVideoData();
            String soundData = ((CPU) obj).getSoundData();
            this.vc.showVideo(videoData);
            this.sc.showSound(soundData);
        }
    }
}
  • 客户端
package design;
/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        Mediator mediator = new MainBoard();
        CDDriver cd = new CDDriver(mediator);
        CPU cpu = new CPU(mediator);
        Video vc = new Video(mediator);
        Sound sc = new Sound(mediator);
        mediator.setCDDriver(cd);
        mediator.setCPU(cpu);
        mediator.setSoundCard(sc);
        mediator.setVideoCard(vc);
        //光驱读数据,通知中介者,中介者通知CPU去分离数据,CPU分离数据完成,通知中介者,中介者通知声卡和显卡播放
        cd.readCD("终结者,终结者音频");
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 1 场景问题# 1.1 如果没有主板## 大家都知道,电脑里面各个配件之间的交互,主要是通过主板来完成的(事实上主...
    七寸知架构阅读 2,157评论 0 56
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,567评论 18 399
  • 设计模式是解决特定问题的一系列套路。设计模式的使用不是语法规定,不要为了套用设计模式而用设计模式,它的使用为了解决...
    闲庭阅读 7,377评论 2 18
  • 秋燥令人咳 茫茫一片雾 落不下的雀啾 枯了残荷的筋骨 勾起谁难以想象的梦境 起了 碎了 终不过是你 的 一点痴想 ...
    叶抽抽阅读 182评论 0 0