java常见的设计模式
在了解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常见的设计模式相关推荐
- Java常见的设计模式整理
设计模式六大原则 1.开放封闭原则:对扩展开放,对修改封闭,意即程序拓展时不要动原有的代码 2.LSP原则:任何基类可以出现的地方,子类一定可以出现 3.依赖倒置原则:使用接口,依赖于抽象而不是具体 ...
- ☀️一张思维图带大家了解Java常见设计模式☀️《❤️记得收藏❤️》
☀️一张思维图带大家了解Java常见设计模式☀️<❤️记得收藏❤️> 目录
- java 常用十种设计模式示例归纳 | 已打包请带走
设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结. GitHub地址 DesignPattern 文章说明 一个Demo,集合常用的十种设计模 ...
- java中单例设计模式登记式单例类_java23种设计模式-创建型模式之单例模式
单例模式(Singleton) 单例对象(Singleton)是一种常用的设计模式.在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在.这样的模式有几个好处: 1.某些类创建比较频 ...
- Java常见面试知识点:继承、接口、多态、代码块
问题:Java常见面试知识点:继承.接口.多态.代码块 答案: 1.继承 继承中构造方法的访问特点 子类中所有的构造方法默认都会访问父类中无参的构造方法 为什么? • 子类在初始化的时候,有可能会使用 ...
- 视频教程:Java常见面试题目深度解析!
视频教程:Java常见面试题目深度解析! Java作为目前比较火的计算机语言之一,连续几年蝉联最受程序员欢迎的计算机语言榜首,因此每年新入职Java程序员也数不胜数.很多java程序员在学成之后,会面 ...
- Java基础篇--设计模式
目录 前言 设计模式 创建型模式 单例模式 工厂方法模式 抽象工厂模式 建造者模式 原型模式 结构型模式 适配器模式 桥接模式 组合模式 装饰模式 外观模式 亨元模式 代理模式 行为型模式: 访问者模 ...
- 常见的设计模式和应用场景
常见的设计模式和应用场景 单例模式 原型模式 命令模式 六大设计原则 1. 单一职责原则 2. 开闭原则 3. 里氏替换原则 4. 依赖倒置原则 5. 接口隔离原则 6. 迪米特法则 设计模式从大的维 ...
- 黑马程序员-Java基础:设计模式总结
--Java培训.Android培训.iOS培训..Net培训.期待与您交流! -- Java基础部分设计模式 一.设计模式概述 设计模式(Design pattern)是一套被反复使用.多数人知晓的 ...
最新文章
- 中国开源大爆发进行时,你没掉队吧?
- MySQL数据库中默认事务隔离级别是?
- 面试02.01移除重复结点
- 计算机视觉黑魔法 | 16个案例
- 几种简单的滤波方式(未完)
- 编译Bitcoin BCH configure: error: libdb_cxx headers missing ,终于解决了
- P1650 田忌赛马(贪心)
- C# 配置文件 自定義結點
- 数据结构--赫夫曼树及其应用
- Java8 函数式编程之函数接口(上)
- ebay 后台HTML有尺寸宽度要求吗,eBay牛仔裤成为尺码问题重灾区,卖家上架需注意这几个方面...
- java的字符串的加密_Java加密解密字符串
- 一体机or复合机?企业文印设备该怎么选
- c#中excel文件怎么转换为dbf文件
- 网站出现502 BAD GATEWAY的解决办法
- win7无法自动获取dns服务器地址,Win7无法自动获取DNS与IP地址怎么办
- 轻音乐-Bandari(班得瑞)
- 作为程序员你应该会的软件
- 这些联盟可以去注册试一下
- google map api v3 的marker使用label的方法(markerwithlabel的使用)
热门文章
- 解决 SharePoint 2013 管理中心登录问题。
- 扎克伯格最新VR原型机来了,要让人混淆虚拟与现实的那种
- 不同cpu matlab,求助大神,为何不同机器运行MATLAB结果不同
- 算法设计与分析之数字三角形问题(C++解法)
- can口通信的软件测试,CAN网络一致性测试和UDS测试设备
- 电脑版适合什么插件HTML,推荐一些好用的Chrome插件
- 使用Node.js express 开发上传文件/图片api接口
- vba中将数字数据转为数字格式_通过VBA将文本格式的时间转换为数字格式
- spring boot+secruity 跨域问题,cookie问题解决
- 路由配置url跳转传参_如何配置路由器以进行网络范围的URL记录