java的版本不断的迭代更新,各种框架和组件也层出不穷,但是设计的思想永远不会变,也许平时只是一个curl工程师,还在代码中看不到任何设计模式的影子,那可太糟心了。设计模式的应用往往也能反应一个程序员的水平,设计模式说到底就是可扩展 可解耦 多封装一些共用行为,就是为了提升代码的可读可用性,设计模式就像写文章一样,没有对错之分,一条语句可以有多种表达方式 修辞手法。
保证类只产生有且只有一个实例。由私有构造函数,共用访问点,一个静态初始变量组成。单例模式分饿汉和懒汉。
饿汉不管需不需要直接实例化,不用考虑多线程冲突问题,可用于配置文件初始化。
package com.orange.demo.design;
public class Single {
private static Single instance = new Single();
// 禁止外部实例化
private Single(){
}
public static Single getInstance(){
return instance;
}
public void execute(){
System.out.println("饿汉");
}
public static void main(String[] args){
Single single = Single.getInstance();
single.execute();
}
}
懒汉是调用时才实例化,线程不安全,可通过双锁机制保证线程安全,多用于对外部客户端的初始化
package com.orange.demo.design;
public class Single {
private static volatile Single instance;//禁止指令重排
// 禁止外部实例化
private Single(){
}
public static Single getInstance(){
if (instance==null) {
synchronized (Single.class){
if (instance==null) {
//防止拿到锁后对象已经实例化
instance = new Single();
}
}
}
return instance;
}
public void execute(){
System.out.println("懒汉");
}
public static void main(String[] args){
Single single = Single.getInstance();
single.execute();
}
}
故名思意,作为一个装饰品添加到原有功能上,不对原有代码做变更,spring中的过滤器和AOP拦截器都是装饰器模式。
装饰器模式由装饰类和被装饰类组成,装饰类继承被装饰类,将被装饰类实例传入装饰类,类似生成一个代理类。
package com.orange.demo.design;
public class House {
public House() {
}
void door(){
System.out.println("我是一扇门");
}
}
package com.orange.demo.design;
public class Decorator extends House {
private House house;
public Decorator(House house) {
this.house = house;
}
@Override
void door() {
super.door();
System.out.println("添加一些装饰");
}
public static void main(String[] args){
Decorator decorator = new Decorator(new House());
decorator.door();
}
}
工厂模式主要处理对象的多态,是开闭原则的一种实现,也就是可拓展 不可修改,工程模式有以下三类。
spring中bean的获取就是一种简单工厂模式,这里不过多赘述
和简单工厂的区别是简单工厂是一个工厂处理所有产品,工厂方法是多个工厂处理不通的产品
public interface IFactory {
IProduct doProduct();
}
public interface IProduct {
void execute();
}
public class IProductImplA implements IProduct {
@Override
public void execute() {
System.out.println("产品A");
}
}
public class IFactoryImplA implements IFactory{
@Override
public IProduct doProduct() {
return new IProductImplA();
}
public static void main(String[] args){
IFactory f = new IFactoryImplA();
f.doProduct().execute();
}
}
抽象工厂模式和工厂方法模式相似,抽象工厂会抽象出一些具体行为,可以直观的看出工厂的功能。
如快递的物流公司选择。工厂中可以抽象出如下单 路由查询等具体行为。不同的物流公司的相同行为由不同的产品类实现,不同的工厂类只处理自家的业务。
建造模式主要场景是对象的实例化或客户端的初始化。相比于构造函数的构造入参不可扩展,建造模式通过链式调用解决这一问题,对入参的一些校验可以放入build方法中,优势就是可扩展,可解耦。
实际应用的场景可以是调用第三方接口时生成入参,这种场景往往是通过本地的数据生成接口需要的入参。
import lombok.Data;
@Data
public class Good {
private String name;
private String price;
public static class Builder {
private String name;
private String price;
public Builder name(String name){
this.name = name;
return this;
}
public Builder price(String price){
this.price = price;
return this;
}
public Good build(){
Good good = new Good();
good.name = this.name;
good.price = this.price;
return good;
}
}
}
public static void main(String[] args){
Good good = new Good.Builder().name("1").price("2").build();
System.out.println(good);
}
顾名思义,购买了国外的电器,电压标准110V,而国内标准为220V,这时候需要一个电压转换器,适配器模式就是让本不兼容的事务可以使用。
拿上述举例,220V为适配者,110V为目标类
public class V220 {
public void execute(){
System.out.println("输出220V的电压");
}
}
public interface Transform {
/**
* 负责电压转换
*/
void transform();
}
/**
* 110V电压转换器
*/
public class V110 implements Transform {
private V220 v220;
public V110(V220 v220) {
this.v220 = v220;
}
@Override
public void transform() {
v220.execute();
System.out.println("输出110V电压");
}
public static void main(String[] args){
V110 v110 = new V110(new V220());
v110.transform();
}
}
适用对需要对输出结果进行转换的场景。
模板是个人对一些流程化的 较复杂的业务常使用的设计模式,拿医疗系统的开立检查检验项目为例,业务流程大概是这么几块,创建就诊卡->科室挂号->项目申请,可能大部分人就是通过controller+接口实现进行开发,这种开发模式时间久了或者接手了别人的代码,这种流程性的行为就很难通过后端代码有一个直观的认识,往往需要通过前端代码确定整个接口流程。如果通过抽象类抽象公有行为,并设置流程模板,并且抽象类不同于接口,抽象类中可以提取并实现一些公有方法,对于后面的扩展是十分方便的。
/**
* 检查检验申请抽象类
*/
@Data
public abstract class AbstractMedTecApply {
//开立检查检验业务代码模板 获取病历号 + 挂号 + 申请
public final void addMedicalTec() throws PBMException {
init();
checkApply();
//挂号
register();
//申请
apply();
}
/**
* 申请前做一些校验
*/
public void checkApply() throws PBMException {
//校验就诊状态
}
//获取his病历号
public void setPatientId(Map<String, Object> outPatientInfo) throws PBMException {
//如果没有his病历号则调用接口获取
}
/**
* 检查检验做各自的初始化
*/
protected abstract void init();
/**
* 挂号 区分检验检查
*
* @throws PBMException
*/
protected abstract void register() throws PBMException;
/**
* 医技申请
*
* @throws PBMException
*/
protected abstract void apply() throws PBMException;
}
代理模式的设计思路参考nginx的反向代理,客户类通过代理类调用委托类。
代理模式和装饰模式很像,说到区别网上有很多,但是我觉得还是参考nginx的反向代理,当调用的时候感知不到委托类的就是代理模式。
代理模式就不写代码了,无非就是隐藏委托类的代码。
使用链表的流程性场景,责任链模式中所有的对象都有一个共用的父类或接口,子类都调用的父类的同一个方法处理业务,子类间链式引用,最终通过父类方法处理多个子类。
下面的代码通过大家最熟悉的请假流程举例
package com.orange.demo.design.chain;
public abstract class Handler {
// 最大请假天数
public int maxDays;
// 部门
public String dept;
public Handler(String dept, int maxDays){
this.dept = dept;
this.maxDays = maxDays;
}
private Handler nextHandler;
public void next(Handler handler){
this.nextHandler = handler;
}
/**
* 请假天数校验
* @param n 申请请假天数
*/
public final void check(int n){
if (this.maxDays>=n) {
this.agree();
} else {
if (this.nextHandler!=null) {
nextHandler.check(n);
} else {
System.out.println("审批不通过");
}
}
}
protected void agree(){
System.out.println("部门 "+ this.dept + " 已同意");
}
}
package com.orange.demo.design.chain;
public class DeptA extends Handler {
public DeptA(String dept, int maxDays) {
super(dept, maxDays);
}
}
package com.orange.demo.design.chain;
public class DeptB extends Handler {
public DeptB(String dept, int maxDays) {
super(dept, maxDays);
}
}
package com.orange.demo.design.chain;
public class DeptC extends Handler {
public DeptC(String dept, int maxDays) {
super(dept, maxDays);
}
}
public static void main(String[] args){
DeptA a = new DeptA("研发部", 5);
DeptB b = new DeptB("主管部", 10);
DeptC c = new DeptC("董事局", 15);
a.next(b);
b.next(c);
a.check(15);
}
享元模式的核心就是享,做到对象共亨,避免创建大量重复变量。
线程池,连接池,字符串常量池都是这类模式的运用。
类似消息队列的发布订阅模式,观察者相当于消费者的角色,多个观察者同时监听某一事件。
public interface Broker {
void addObserver(Observer observer);
void notify(String msg);
}
public class BrokerImpl implements Broker {
private List<Observer> obsList = new ArrayList<>();
@Override
public void addObserver(Observer observer) {
obsList.add(observer);
}
@Override
public void notify(String msg) {
for (Observer ob : obsList) {
ob.getMsg(msg);
}
}
}
public class Observer {
private String name;
public Observer(String name) {
this.name = name;
}
public void getMsg(String msg){
System.out.println(name+"收到消息了 " + msg);
}
}
public static void main(String[] args){
Observer a = new Observer("a");
Observer b = new Observer("b");
Broker broker = new BrokerImpl();
broker.addObserver(a);
broker.addObserver(b);
broker.notify("xxxxxx");
}
策略模式由抽象策略类 策略实现类 上下文类三部分组成,策略模式中通过上下文类实现策略。
乍看下和工厂模式很像,策略模式侧重对单个行为的算法的不同选择,工厂模式的范围比较大,是对多个行为封装到工厂后,再对行为进行实现。策略模式通过将策略实例传入上下文类中实现行为,工厂模式选择工厂后直接调用行为方法。
下面用多种支付方法举例
/**
* 多种支付方式
*/
public interface PayStrategy {
/**
* 支付方式
*/
void payWay();
}
/**
* 支付宝
*/
public class AliStrategy implements PayStrategy {
@Override
public void payWay() {
System.out.println("支付宝支付");
}
}
/**
* 微信
*/
public class WXPayStrategy implements PayStrategy {
@Override
public void payWay() {
System.out.println("微信支付");
}
}
public class PayContext {
private PayStrategy payStrategy;
public PayContext(PayStrategy payStrategy) {
this.payStrategy = payStrategy;
}
public void pay(){
payStrategy.payWay();
}
}
public static void main(String[] args){
PayStrategy ali = new AliStrategy();
PayContext context = new PayContext(ali);
context.pay();
}
上面列举了部分设计模式,可以发现很多设计模式的思想都是相似的,就像张三丰教张无忌太极一样,设计模式是一种解决问题的思想,没有固定的套路。
快去使用设计模式吧!!!
to be continue…
文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99
文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效
文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是
文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件
文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件
文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码
文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware
文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停
文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待
文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析
文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code
文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象