在了解java常见的设计模式之前,我们要了解三个问题,

1.为什么要了解设计模式?

2.这些设计模式的是根据什么原则来设计的?

3.有哪些常见的设计模式?

  • 为什么要了解设计模式?

因为设计模式代表了最佳的实践,是很多优秀的软件开发人员的经验总结,恰当的使用设计模式可以增强代码的可复用性,可维护性,可扩展性,健壮性及安全性。

  • 这些设计模式的是根据什么原则来设计的?

这些设计模式的基础其实就是java面向对象,而且大部分的设计原则就是根据oop的设计原则(开闭原则、里氏替换原则、迪米特原则(最少知识原则)、单一职责原则(DIP)、接口分离原则(ISP)、依赖倒置原则、组合/聚合复用原则),目的很简单,就是体现java三大特点,为了更好的体现出程序、代码的灵活性。

  • 有哪些常见的设计模式?

经典的设计模式有23种,此篇文章介绍4种常见的设计模式,单例模式、工厂模式、责任链模式和观察者模式。

1.单例模式

1.1 概念

顾名思义,保证在内存中只用一个实例

1.2 使用场景

比如:系统配置文件的管理,这些配置文件只要使用一个单例对象进行读写即可,系统总其他地方需要使用配置信息时,只要使用该单例对象进行获取就可以了,这样便于统一管理配置信息。

1.3 优缺点

优点:

  • 在内存中只有一个对象,节省内存空间;
  • 避免频繁的创建销毁对象,可以提高性能;
  • 避免对共享资源的多重占用,简化访问;
  • 为整个系统提供一个全局访问点。

缺点:

  • 不适用于变化频繁的对象;
  • 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;

1.4 示例

饥饿模式

/*** 单例模式,饥饿加载*/
public class SingletonDemo {//1. 需要有一个私有的构造函数,防止该类通过new的方式创建实例private SingletonDemo(){}//2. 饥饿模式,首先生成一个实例private static final SingletonDemo instance = new SingletonDemo();//3. 静态方法,用于获取已经生成的实例public static SingletonDemo getInstance() {return instance;}public String hello(String name) {return "hello " + name;}}

这种直线方式简单,在加载类的时候就会创建好实例,等待被调用,且是线程安全的。

懒汉模式

第一种写法:

/*** 单例模式: 懒汉式*/
public class SingletonDemo02 {private SingletonDemo02(){}private static SingletonDemo02 singletonDemo02 = null;public static SingletonDemo02 getInstance() {if (singletonDemo02 == null) {singletonDemo02 = new SingletonDemo02();}return singletonDemo02;}public String hello(String name) {return "hello " + name;}}

注意: 这种方式在多线程访问时会有问题,具体原因就是如果线程多的时候,由于时间片的轮换机制,可能会导致产生多个实例。

第二种写法:

/*** 单例模式: 懒汉式,线程安全,但性能较低*/
public class SingletonDemo03 {private SingletonDemo03() {}private static SingletonDemo03 singletonDemo03 = null;public static synchronized SingletonDemo03 getInstance(){if(singletonDemo03 == null) {singletonDemo03 = new SingletonDemo03();}return singletonDemo03;}public String hello(String name) {return "hello " + name;}}

第三种写法:

public class SingletonDemo03 {private SingletonDemo03() {}private static SingletonDemo03 singletonDemo03 = null;public static  SingletonDemo03 getInstance(){//系统减小同步块来提升性能if(singletonDemo03 == null) {synchronized (SingletonDemo03.class) {singletonDemo03 = new SingletonDemo03();}}return singletonDemo03;}public String hello(String name) {return "hello " + name;}}

该方式依然会有线程安全问题,原因跟第一种原因一种

第四种写法:

/*** 单例模式: 懒汉式,双重检查单例*/
public class SingletonDemo03 {private SingletonDemo03(){}private static SingletonDemo03 singletonDemo03 = null;public static  SingletonDemo03 getInstance(){//减小同步块,并使用双重检查来保证线程安装if(singletonDemo03 == null) {synchronized (SingletonDemo03.class) {if(singletonDemo03 == null) {singletonDemo03 = new SingletonDemo03();}}}return singletonDemo03;}public String hello(String name) {return "hello " + name;}}

第五种写法:

/*** 单例模式: 懒加载, 线程安全*/
public class SingletonDemo04 {//阻止外部实例化private SingletonDemo04(){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}//使用静态内部类来使用一个SingletonDemo04对象private static class SingletonDemoHolder {private final static SingletonDemo04 instance = new SingletonDemo04();}public static SingletonDemo04 getInstance() {return SingletonDemoHolder.instance;}public String hello(String name) {return "hello " + name;}}

第六种写法:

public enum  SingletonDemo05 {INSTANCE;public String hello(String name) {return "hello " + name;}}

可以保证单例,且线程安全,同时也是最简单的,因为枚举类型不能够被实例化,前5种方式还是可以通过java的反射机制获取新的实例,但是枚举类型的不可以,因为一运行,就由java虚拟机jvm实例,别人是示例不了的。

2 工厂模式

2.1 概念

用于产生对象的方法或者式类,称之为工厂。 上面所讲到的单例模式也可以看作为一个特殊的工厂。

2.2 使用场景

为什么需要工作模式,原来使用new的方式感觉也很简单啊,而且也很容易看明白啊。

使用工厂的原因是我们可以通过工厂模式,来集中控制对象的创建过程,这样可以给设计带来更多的灵活性。

比如:spring的IOC容器就是工厂模式的经典实现。

2.3 工厂方法(简单工厂)

用于生产指定系列的对象。已鸭子为例,鸭子有真的鸭子,橡皮鸭,电子玩具鸭等。如何能方便的创建出各种鸭子,并将创建过程控制起来,以便于以后的维护和扩展

类图:

代码:

抽象类,鸭子的规范类

public abstract class Duck {abstract public void quack();}

三个子类

public class RubberDuck extends Duck {@Overridepublic void quack() {System.out.println("我是橡皮鸭,");}}
public class WildDuck extends Duck {@Overridepublic void quack() {System.out.println("我是真鸭子");}}
public class DonaldDuck extends Duck {@Overridepublic void quack() {System.out.println("我是唐老鸭");}}

工厂类

public class DuckFactory {private DuckFactory(){}private static DuckFactory duckFactory = new DuckFactory();public static final int WILD_DUCK = 1;public static final int RUBBER_DUCK = 2;public static final int DONALD_DUCK = 3;public static final int PJ_DUCK = 4;public static final int ZH_DUCK = 5;public static Duck getInstance(int duckType) {switch (duckType) {case WILD_DUCK:return new WildDuck();case RUBBER_DUCK:return new RubberDuck();case DONALD_DUCK:return new DonaldDuck();case PJ_DUCK:return new PJDuck();case ZH_DUCK:return new ZhouHeiDuck();default:return null;}}

测试类

public class Main {public static void main(String[] args) {Duck donaldDuck = DuckFactory.getInstance(DuckFactory.DONALD_DUCK);donaldDuck.quack();Duck wildDuck = DuckFactory.getInstance(DuckFactory.WILD_DUCK);wildDuck.quack();}}

输出结果:

我是唐老鸭
        我是真鸭子

好处:只要给定特定的鸭子类型,就可以实例化出对应的实体,这样会利于修改和拓展,体现出更好的灵活性。

2.4 抽象工厂

用于生成指定产品族,一个产品族中包括多种产品。例如:
我们都比较熟悉的电脑制造相关行业,有HP,罗技,联想,戴尔,近几年华为,小米也进来了,每个生产商生产的电脑又包括鼠标,键盘,屏幕等等配件。此时我们需要使用工厂模式来进行管理不同的产品族,这时使用简单工厂(也有叫作工厂方法的)已经无法满足要求,此时可以使用抽象工厂。

类图:

示例代码:

PcFactory(类族)


public abstract class PcFactory {//制作方法public abstract Mouse makeMouse();public abstract Keyboard makeKeyboard();//为得到具体的工厂的方法服务private static HpFactory hpFactory = new HpFactory();private static LogicFactory logicFactory = new LogicFactory();//为得到具体的工厂的方法服务public final static int PC_TYPE_HP = 1;public final static int PC_TYPE_LG = 2;/*** 得到具体的工厂的方法* @param pcType传入表示电脑类型的常数* @return 返回PcFactory抽象类:面向抽象编程代替面向具体编程*/public static PcFactory getPcFactory(int pcType) {switch (pcType){case 1:return hpFactory;case 2 :return logicFactory;default:return null;}}
}

        HPFactory(惠普)工厂

public class HpFactory extends PcFactory {//返回抽象类:面向抽象编程代替面向具体编程@Overridepublic Mouse makeMouse() {return new HpMouse();}@Overridepublic Keyboard makeKeyboard() {return new HpKeyboard();}}

        LogicFactory(罗技)子工厂(继承抽象类PcFactory)

public class LogicFactory extends PcFactory {@Overridepublic Mouse makeMouse() {return new LogicMouse();}@Overridepublic Keyboard makeKeyboard() {return new LogicKeyboard();}
}

        鼠标抽象工厂Keyboard

public abstract class Keyboard {abstract String getInfo();
}

        Hpkeyboard(HP的键盘制作工厂)


public class HpKeyboard extends Keyboard {@OverrideString getInfo() {return "HP keyboard";}
}

        LogicKeyboard(Logic的键盘制作工厂)

public class LogicKeyboard extends Keyboard {@OverrideString getInfo() {return "logic keyboard";}
}

        键盘抽象工厂Mouse

public abstract class Mouse {abstract String getInfo();
}

         HpMouse(HP的鼠标制作工厂)

public class HpMouse extends Mouse {@OverrideString getInfo() {return "HP mouse";}
}

        LogicMouse (Logic的鼠标制作工厂)

public class LogicMouse extends Mouse {@OverrideString getInfo() {return "logic mouse";}
}

        测试

public class Main {public static void main(String[] args) {//通过抽象PcFactory父类得到HP电脑制作工厂PcFactory HpFactory = PcFactory.getPcFactory(PcFactory.PC_TYPE_HP);//得到HP制作键盘的方法Keyboard keyboard = HpFactory.makeKeyboard();//得到HP制作鼠标的方法Mouse mouse = HpFactory.makeMouse();System.out.println(keyboard.getInfo());System.out.println(mouse.getInfo());}}

结果:

HP keyboard
        HP mouse

3.责任链模式

3.1 概念

        责任链模式是一个对象的行为模式,很多对象之间形成一条链条,处理请求在这个链条上进行传递,直到责任链的上的某个对象决定处理请求(也可扩展为几个对象处理),这个过程对于用户来说是透明的,也就是说用户并不需要知道是责任链上的哪个对象处理的请求,对请求是否处理由链条上的对象自己决定。

为了便于理解我们可以想象一下击鼓传花的游戏。

        3.2 使用场景

  web容器中的过滤器算是责任链模式的一个经典场景。另外举个例子:当在论坛上提交内容时,论坛系统需要对一些关键词进行处理,看看有没有包含一些敏感词汇,而这些敏感词汇我们可以使用责任链模式进行处理。

3.3 类图

代码:

Filter接口

/*** Filter接口,实际上是对变化的抽象* 这种方式会逐个的运行Filter,但不能* 指定是否需要继续执行后面的Filter。* 比如:当发现违法了特殊符号的Filter时* 其后的过滤链没有必要执行*/
public interface Filter {void doFilter(Message message);}

CheckSyntaxFiler(对语法结构进行检查)

对语法进行检查不能出现”<>”如果出现了用“#”替换

public class ChackSyntaxFilter implements Filter {@Overridepublic void doFilter(Message message) {String content = message.getContent();content = content.replace("<", "#");content = content.replace(">", "#");message.setContent(content);}}

        WordFilter(敏感词的过滤)

        若出现敏感词汇用”***”替换

public class WordFilter implements Filter {@Overridepublic void doFilter(Message message) {String content = message.getContent();content = content.replace("嘻嘻", "***");content = content.replace("hha", "***");message.setContent(content);}}

        FilterChain(过滤器链)

/*** 将Filter组织成一个链条*/
public class FilterChain {private FilterChain(){}private static List<Filter> filters = new ArrayList<>();private static FilterChain instance = new FilterChain();public static FilterChain getInstance(){return instance;}public FilterChain add(Filter filter) {filters.add(filter);return this;}public Message dofilters(final Message message) {for (Filter f : filters) {f.doFilter(message);}return message;}}

        Message(demo)

package com.zking.patterndemo;public class Message {private String content;public String getContent() {return content;}public void setContent(String content) {this.content = content;}@Overridepublic String toString() {return "Message{" +"content='" + content + '\'' +'}';}
}

        测试


public class Main {public static void main(String[] args) {Message msg = new Message();msg.setContent("hello, <abc>, hhaxx嘻嘻, 哈哈哈");FilterChain fc = FilterChain.getInstance();fc.add(new ChackSyntaxFilter()).add(new WordFilter()).dofilters(msg);System.out.println(msg.getContent());}}

结果:

hello,#abc#,***xx***,哈哈哈

4.观察者模式

4.1 概念

观察者模式是对象的行为模式,有时也称为“发布/订阅模式”或者“监听器模式”。

观察者模式定义了观察者和被观察者之间的一对多的关系,让多个观察者对象可以响应一个被观察者对象。

4.2 使用场景

比较经典的使用场景,比如:java中的swing包中对事件的处理。浏览器对鼠标,键盘等事件的处理等, spring中的事件发布机制也是使用该模式。

4.3 类图

代码

Observer(观察者接口)


public interface Observer {void bell(BellEvent event);
}

Nurse(护士)

public class Nurse implements Observer {@Overridepublic void bell(BellEvent event) {System.out.println("I am nurse, Can I help you?");}
}

        Docter(医生)


public class Docter implements Observer {@Overridepublic void bell(BellEvent event) {System.out.println("I am docter, Can I help you?");}
}

        Wife(妻子)

public class Wife implements Observer {@Overridepublic void bell(BellEvent event) {System.out.println("baby, I am here, Don't worry !");}
}

Event(总事件)


public abstract class Event {protected Object source;public Object getSource() {return this.source;}}

        BellEvent(事件实现类)


public class BellEvent extends Event {long timestamp;public BellEvent(Object source) {this.timestamp = System.currentTimeMillis();this.source = source;}}

        Patient(患者)


public class Patient {private List<Observer> observers = new ArrayList<>();public void addObserver(Observer observer) {observers.add(observer);}public void ringBell() {BellEvent event = new BellEvent(this);for (Observer observer: observers) {observer.bell(event);}}}

测试


public class Main {public static void main(String[] args) {Patient patient = new Patient();patient.addObserver(new Docter());patient.addObserver(new Nurse());patient.addObserver(new Wife());patient.ringBell();}
}

结果:

I am docter, Can I help you?
        I am nurse, Can I help you?
        baby, I am here, Don't worry !

4.4 小结

观察者模式是使用的非常广泛,比如:Listener,Hook,Callback等等,其实都是观察者的一种应用,名称叫法不同而已,思路基本相同。

总结

这些都是比较继承的设计模式,很多框架都会运用这些设计模式,只有理解了这些设计模式,才能更好的去了解和使用框架

java常见的设计模式相关推荐

  1. Java常见的设计模式整理

    设计模式六大原则 1.开放封闭原则:对扩展开放,对修改封闭,意即程序拓展时不要动原有的代码 2.LSP原则:任何基类可以出现的地方,子类一定可以出现 3.依赖倒置原则:使用接口,依赖于抽象而不是具体 ...

  2. ☀️一张思维图带大家了解Java常见设计模式☀️《❤️记得收藏❤️》

    ☀️一张思维图带大家了解Java常见设计模式☀️<❤️记得收藏❤️> 目录

  3. java 常用十种设计模式示例归纳 | 已打包请带走

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结. GitHub地址 DesignPattern 文章说明 一个Demo,集合常用的十种设计模 ...

  4. java中单例设计模式登记式单例类_java23种设计模式-创建型模式之单例模式

    单例模式(Singleton) 单例对象(Singleton)是一种常用的设计模式.在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在.这样的模式有几个好处: 1.某些类创建比较频 ...

  5. Java常见面试知识点:继承、接口、多态、代码块

    问题:Java常见面试知识点:继承.接口.多态.代码块 答案: 1.继承 继承中构造方法的访问特点 子类中所有的构造方法默认都会访问父类中无参的构造方法 为什么? • 子类在初始化的时候,有可能会使用 ...

  6. 视频教程:Java常见面试题目深度解析!

    视频教程:Java常见面试题目深度解析! Java作为目前比较火的计算机语言之一,连续几年蝉联最受程序员欢迎的计算机语言榜首,因此每年新入职Java程序员也数不胜数.很多java程序员在学成之后,会面 ...

  7. Java基础篇--设计模式

    目录 前言 设计模式 创建型模式 单例模式 工厂方法模式 抽象工厂模式 建造者模式 原型模式 结构型模式 适配器模式 桥接模式 组合模式 装饰模式 外观模式 亨元模式 代理模式 行为型模式: 访问者模 ...

  8. 常见的设计模式和应用场景

    常见的设计模式和应用场景 单例模式 原型模式 命令模式 六大设计原则 1. 单一职责原则 2. 开闭原则 3. 里氏替换原则 4. 依赖倒置原则 5. 接口隔离原则 6. 迪米特法则 设计模式从大的维 ...

  9. 黑马程序员-Java基础:设计模式总结

    --Java培训.Android培训.iOS培训..Net培训.期待与您交流! -- Java基础部分设计模式 一.设计模式概述 设计模式(Design pattern)是一套被反复使用.多数人知晓的 ...

最新文章

  1. 中国开源大爆发进行时,你没掉队吧?
  2. MySQL数据库中默认事务隔离级别是?
  3. 面试02.01移除重复结点
  4. 计算机视觉黑魔法 | 16个案例
  5. 几种简单的滤波方式(未完)
  6. 编译Bitcoin BCH configure: error: libdb_cxx headers missing ,终于解决了
  7. P1650 田忌赛马(贪心)
  8. C# 配置文件 自定義結點
  9. 数据结构--赫夫曼树及其应用
  10. Java8 函数式编程之函数接口(上)
  11. ebay 后台HTML有尺寸宽度要求吗,eBay牛仔裤成为尺码问题重灾区,卖家上架需注意这几个方面...
  12. java的字符串的加密_Java加密解密字符串
  13. 一体机or复合机?企业文印设备该怎么选
  14. c#中excel文件怎么转换为dbf文件
  15. 网站出现502 BAD GATEWAY的解决办法
  16. win7无法自动获取dns服务器地址,Win7无法自动获取DNS与IP地址怎么办
  17. 轻音乐-Bandari(班得瑞)
  18. 作为程序员你应该会的软件
  19. 这些联盟可以去注册试一下
  20. google map api v3 的marker使用label的方法(markerwithlabel的使用)

热门文章

  1. 解决 SharePoint 2013 管理中心登录问题。
  2. 扎克伯格最新VR原型机来了,要让人混淆虚拟与现实的那种
  3. 不同cpu matlab,求助大神,为何不同机器运行MATLAB结果不同
  4. 算法设计与分析之数字三角形问题(C++解法)
  5. can口通信的软件测试,CAN网络一致性测试和UDS测试设备
  6. 电脑版适合什么插件HTML,推荐一些好用的Chrome插件
  7. 使用Node.js express 开发上传文件/图片api接口
  8. vba中将数字数据转为数字格式_通过VBA将文本格式的时间转换为数字格式
  9. spring boot+secruity 跨域问题,cookie问题解决
  10. 路由配置url跳转传参_如何配置路由器以进行网络范围的URL记录