当前位置:网站首页>常见设置模式
常见设置模式
2022-06-21 16:04:00 【時宜】
目录
1. 为什么需要学习设计模式
设计模式(Design pattern)代表了最佳的实践,是很多优秀的软件开发人员的经验总结,是解决特定问题的解决方案。它并不是语法规定,也不拘泥于特定语言。 恰当的使用设计模式可以代码的可复用性,可维护性,可扩展性,健壮性及安全性,这些都是系统非常重要的非功能性需求。
设计模式的广泛使用起始于1995年,GOF(四人帮)出版的《设计模式:可复用面向对象软件基础》。
本部分相关的示例代码:
https://gitee.com/lisenaq/patterndemo.git二、常见设置模式
2.1 单例模式
2.1.1 概念
保证在内存中只用一个实例
2.1.2 使用场景
比如:系统配置文件的管理,这些配置文件只要使用一个单例对象进行读写即可,系统总其他地方需要使用配置信息时,只要使用该单例对象进行获取就可以了,这样便于统一管理配置信息。
2.1.3 优缺点
*优点:
- 在内存中只有一个对象,节省内存空间;
- 避免频繁的创建销毁对象,可以提高性能;
- 避免对共享资源的多重占用,简化访问;
- 为整个系统提供一个全局访问点。
*缺点:
- 不适用于变化频繁的对象;
- 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;
2.1.4 示例
1.饥饿模式:直接实例化对象
package org.lisen.patterndemo.singleton;
/**
* 单例模式,饥饿加载
*/
public class SingletonDemo01 {
//1. 需要有一个私有的构造函数,防止该类通过new的方式创建实例
private SingletonDemo01(){}
//2. 饥饿模式,首先生成一个实例
private static final SingletonDemo01 instance = new SingletonDemo01();
//3. 静态方法,用于获取已经生成的实例
public static SingletonDemo01 getInstance() {
return instance;
}
public String hello(String name) {
return "hello " + name;
}
/*
* 测试多线程下单例模式是否安全
* @param args
*/
public static void main(String[] args) {
/*for (int i = 0; i < 100; i++) {
new Thread(()->{
System.out.println(SingletonDemo01.getInstance().hashCode());
}).start();
}*/
SingletonDemo01 s = SingletonDemo01.getInstance();
String hello_world = s.hello("hello world");
System.out.println(hello_world);
}
}
这种直线方式简单,且是线程安全的。
2.懒汉模式:调用方法时进行实例化对象。
- 第一种写法:
/**
* 单例模式: 懒汉式
*/
public class SingletonDemo02 {
private SingletonDemo02(){
//模拟构造函数的运行耗时
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
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;
}
}注意: 这种方式在多线程访问时会有问题。
- 第二种写法:
在上一个方法的基础上增加了同步锁synchronized
package org.lisen.patterndemo.singleton;
/**
* 单例模式: 懒汉式, 有线程问题
*/
public class SingletonDemo03 {
private SingletonDemo03(){
//模拟构造函数的运行耗时
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static SingletonDemo03 singletonDemo02 = null;
public static synchronized SingletonDemo03 getInstance() {
if (singletonDemo03 == null) {
singletonDemo03 = new SingletonDemo03();
}
return singletonDemo03;
}
public String hello(String name) {
return "hello " + name;
}
/*
* 测试多线程下单例模式是否安全
* @param args
*/
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
System.out.println(SingletonDemo03.getInstance().hashCode());
}).start();
}
}
}- 第三种写法
public class SingletonDemo04 {
private SingletonDemo04() {
}
private static SingletonDemo04 singletonDemo04 = null;
public static SingletonDemo04 getInstance(){
//系统减小同步块来提升性能,可以吗?
if(singletonDemo04 == null) {
synchronized (SingletonDemo04.class) {
singletonDemo04 = new SingletonDemo04();
}
}
return singletonDemo04;
}
public String hello(String name) {
return "hello " + name;
}
}该方式依然会有线程安全问题
- 第四种写法
在上个方法基础上进行双重检查 首先判断是否为空 如果为空则加上同步锁 之后再 第二次判断
package org.lisen.patterndemo.singleton;
/**
* 单例模式: 懒汉式,线程安全,但性能较低
*/
public class SingletonDemo05 {
private SingletonDemo05() {
//模拟构造函数的运行耗时
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static SingletonDemo05 singletonDemo05 = null;
public static SingletonDemo05 getInstance(){
//系统减小同步块来提升性能,可以吗?
if(singletonDemo05 == null) {
///....
synchronized (SingletonDemo05.class) {
if(singletonDemo05 == null) {
singletonDemo05 = new SingletonDemo05();
}
}
}
return singletonDemo05;
}
public String hello(String name) {
return "hello " + name;
}
/*
* 测试多线程下单例模式是否安全
* @param args
*/
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
System.out.println(SingletonDemo05.getInstance().hashCode());
}).start();
}
}
}
- 第五种写法
写一个静态的内部类 在静态的内部类里面声明一个静态的实例(是一个单线程没有线程安全问题)
package org.lisen.patterndemo.singleton;
/**
* 单例模式: 懒加载, 线程安全
*/
public class SingletonDemo04 {
//阻止外部实例化
private SingletonDemo04() {
//模拟构造函数运行耗时
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static {
}
//使用静态内部类来使用一个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;
}
/*
* 测试多线程下单例模式是否安全
* @param args
*/
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
System.out.println(SingletonDemo04.getInstance().hashCode());
}).start();
}
}
}
- 第六种写法
enum 枚举型(没有构造函数) 可以保证单例,且线程安全
package org.lisen.patterndemo.singleton;
public enum SingletonDemo05 {
INSTANCE;
public String hello(String name) {
return "hello " + name;
}
/*
* 测试多线程下单例模式是否安全
* @param args
*/
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(SingletonDemo05.INSTANCE.hashCode());
}).start();
}
}
}
注意:单例模式既要保证懒加载也要保证线程安全
2.2 工厂模式
2.2.1 概念
用于产生对象的方法或者式类,称之为工厂。 上面所讲到的单例模式也可以看作为一个特殊的工厂。
2.2.2 使用场景
为什么需要工作模式,原来使用new的方式感觉也很简单,且好懂?
使用工厂的原因是我们可以通过工厂模式,来集中控制对象的创建过程,这样可以给设计带来更多的灵活性。比如:spring的IOC容器就是工厂模式的经典实现。
2.2.3 工厂方法
用于生产指定系列的对象。已鸭子为例,鸭子有真的鸭子,橡皮鸭,电子玩具鸭等。如何能方便的创建出各种鸭子,并将创建过程控制起来,以便于以后的维护和扩展?
类图:

抽象鸭子父类Duck
public abstract class Duck {
abstract public void quack();
}RubberDuck鸭子子类,继承Duck抽象父类
public class RubberDuck extends Duck {
@Override
public void quack() {
System.out.println("我是橡皮鸭,");
}
}WildDuck鸭子子类,继承Duck抽象父类
public class WildDuck extends Duck {
@Override
public void quack() {
System.out.println("我是真鸭子");
}
}DonaldDuck鸭子子类,继承Duck抽象父类
public class DonaldDuck extends Duck {
@Override
public void quack() {
System.out.println("我是唐老鸭");
}
}编写控制鸭子类创建的工厂DuckFactory
public class DuckFactory {
//私有化构造方法
private DuckFactory(){}
//static 饿汉模式实例出一个类型为鸭子工厂类的对象
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 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();
default:
return null;
}
}
}测试
public class Main {
public static void main(String[] args) {
//DuckFactory可以生产鸭子对象
Duck donaldDuck = DuckFactory.getInstance(DuckFactory.DONALD_DUCK);
donaldDuck.quack();
Duck wildDuck = DuckFactory.getInstance(DuckFactory.WILD_DUCK);
wildDuck.quack();
Duck pjDuck = DuckFactory.getInstance(DuckFactory.PJ_DUCK);
pjDuck.quack();
}
}以上就是关于常见设置模式01的内容
边栏推荐
猜你喜欢

exness:美国通货膨胀影响太大,美联储大佬纷纷表态

进击的程序员,如何提升研发效能?|直播预告

Exness: the impact of inflation in the United States is too great, and the leaders of the Federal Reserve have expressed their position one after another

Yaml file details

20 pyGame module to make a jumping ball game

PowerPoint tutorial, how to change page orientation and slide size in PowerPoint?
![[ROS2 基础] Navigation2 导航系统介绍](/img/7f/ad6af972460d7a78fb28d9b4c24477.png)
[ROS2 基础] Navigation2 导航系统介绍

Pytest-- generate test report

Elegant request retry using guzzle Middleware

Notice on the third national operation research / data, model and decision-making course teaching seminar in 2022
随机推荐
新增Razor组件支持代理连接RDP,JumpServer堡垒机v2.23.0发布
exness:美国通货膨胀影响太大,美联储大佬纷纷表态
「运维有小邓」Active Directory批量修改用户
Pytest-- generate test report
【mysql学习笔记11】排序查询
第13周总结博客(校历第15周)动态规划总结
【Leetcode】297. Serialization and deserialization of binary tree (difficult)
线段树&树状数组模板
List set map in kotlin
Alibaba cloud server + pagoda panel + no domain name deployment web project
还在用 Xshell ?试试这款炫酷的 SSH 终端工具吧,功能很强大!
Variables and pointers
高精度压位模板
模板:P6114 【模板】Lyndon 分解&Runs(字符串)
[MySQL learning notes 18] constraints
【Leetcode】297. 二叉树的序列化与反序列化 (困难)
【毕业N年系列】 毕业第四年
[SQLite] résoudre le jeton non enregistré: ''
[ros2 basics] Introduction to navigation2 navigation system
SCAU软件工程基础