关于设计模式:利用中介模式开发全局控制器

中介模式定义了一个独自的(中介)对象,来封装一组对象之间的交互。将这组对象之间的交互委派给与中介对象交互,来防止对象之间的间接交互。在理论的我的项目中,程序由许多对象组成,对象间的交换盘根错节。 随着应用程序的规模增大,对象越来愈多,他们之间的关系也越来简单。对象间很容易呈现互相援用而导致程序无奈运行。同时开发者须要扭转或者删除某一个对象时候,须要查找并且革新所有援用到它的对象。这样一来,革新的老本会变的十分高。 但中介者模式能够让各个对象之间得以解耦。 之前的场景下,如果 A 产生了扭转,开发者须要批改 B、D、E、F 4 个对象,而通过中介者模式,咱们只须要批改中介者这一个对象即可。 中介者的益处是简化了对象之间的交互,害处则是中介类有可能会变成大而简单的“上帝类”(God Class)。所以,在应用中介者模式时候,设计上肯定要十分克服。 理论应用在前端我的项目开发的过程中,有很多业务无关的性能,但这些性能会散落在各个业务中,难以治理,咱们利用中介者模式的思维来构建一个的控制器。 根底控制器// axios 申请工具import axios from "axios";// mitt 微型公布订阅工具import mitt from "mitt";const createApi = ($controller) => { const api = axios.create({ baseURL: "/api", timeout: 10000, }); api.interceptors.request.use(() => { // 能够通过 $controller.tmpCache 缓存一些数据 }); return api;};const createBus = () => mitt();class Controller { // 长期缓存,也能够增加更简单的缓存 tmpCache: Record<string, any> = {}; // 事件总线 bus = createBus(); constructor() { this.api = createApi(this); } static instance: Controller | null = null; static getInstance() { if (!Controller.instance) { Controller.instance = new Controller(); } return Controller.instance; }}export default Controller;此时控制器中有一个极简的缓存 tmpCache,公布订阅工具。以及服务端申请办法 api。开发者只须要导入 Controller 类即可应用。如果后续须要更加简单的缓存或者革新 api(如切换为 fetch)申请办法。开发者能够很快的进行替换。而无需革新对应文件。 ...

September 10, 2023 · 2 min · jiezi

关于设计模式:遇到无序多变请求怎么办可以试试责任链模式

责任链模式(Chain Of Responsibility Design Pattern),也叫做职责链,是将申请的发送和接管解耦,让多个接管对象都有机会解决这个申请。当有申请产生时,可将申请沿着这条链传递,直到有对象解决它为止。一、责任链模式介绍其实在日常生活中,有不少应用责任链的场景。比方公司洽购审批流程,须要各个部门领导的批准批准。在责任链模式中,客户端只须要将申请发送到责任链上,毋庸关怀申请的解决细节和传递,申请会主动进行传递。 1.1 责任链模式的构造责任链模式构造的外围在于引入了一个形象解决类,所以次要蕴含两个局部 一个形象Handler类 因为责任链的存在,须要定义下一个handler的援用,能力造成一个链条有了下一个handler援用,所以要对援用进行调用和治理,于是须要setNext() 和getNext() 办法此外因为不同handler解决申请的形式不统一,所以要在其中定义一个形象的申请办法handleRequest()一系列具体的Handler解决类具体构造大抵如下所示: abstract Handler:形象解决者,定义一个解决申请的接口,外部蕴含形象解决办法和后继具体解决者Handler1、Handler2:具体解决者,具体实现形象解决者的办法,并对申请做一些逻辑解决Client:客户端,应用职责链模式1.2 职责链模式的实现依据下面的类图,能够实现如下代码: /** * @description: 形象解决类 * @date: 2022/4/4 */public abstract class Handler { private Handler successor; public Handler getSuccessor() { return successor; } public void setSuccessor(Handler successor) { this.successor = successor; } /** * 解决申请的形象办法 * @param request 申请 */ public abstract void handleRequest(String request);}/** * @description: 具体解决者1 * @date: 2022/4/4 */public class Handler1 extends Handler{ private String handler; public Handler1(String handler) { this.handler = handler; } @Override public void handleRequest(String request) { if ("handler1".equals(request)) { System.out.println("具体解决者handler1进行申请解决"); } else { if (getSuccessor() != null) { //如果指向下一个具体解决者 getSuccessor().handleRequest(request); } else { System.out.println("没有解决者进行解决"); } } }}/** * @description: 具体解决者2 * @date: 2022/4/4 */public class Handler2 extends Handler{ private String handler; public Handler2(String handler) { this.handler = handler; } @Override public void handleRequest(String request) { if ("handler2".equals(request)) { System.out.println("具体解决者handler2进行申请解决"); } else { if (getSuccessor() != null) { getSuccessor().handleRequest(request); } else { System.out.println("申请没有被任何解决者解决"); } } }}/** * @description: 客户端类 * @date: 2022/4/4 */public class Client { public static void main(String[] args) { Handler handler1 = new Handler1("handler1"); Handler handler2 = new Handler2("handler2"); handler1.setSuccessor(handler2); handler1.handleRequest("handler1"); handler1.handleRequest("handler2"); }}测试后果: ...

September 9, 2023 · 4 min · jiezi

关于设计模式:还在用ifelse-用策略模式干掉它

策略模式(Strategy Pattern)策略模式是一种行为设计模式,它将一组行为转换为对象, 并使其在原始上下文对象外部可能互相替换。大白话就是比方我写一个登录业务,目前须要满足能通过零碎内、微信等平台进行登录,将来还有可能引入其余的平台,这个时候就能够采纳策略模式,来让不同的平台的登录都有对应的策略门路。 此外对于不同类型的交易方式(信用卡、支付宝、微信),生成惟一ID的策略(UUID、雪花算法、Leaf算法)等,咱们都能够先用策略模式对其进行行为包装,而后提供给外界进行调用。 一、 策略模式介绍在策略模式中,次要有两个局部: 示意各种策略的对象Strategy行为随着策略对象扭转而扭转的原始对象Context,它次要用于散发不同策略对象留神,如果一个零碎中的策略多于四个,就须要思考应用混合模式,解决策略类收缩的问题。上面来看看对应的UML结构图: Stategy:形象策略构造,定义不同策略须要执行的对立步骤和办法ConcreteStrategy1、ConcreteStrategy2:实现形象策略定义的接口,提供具体的算法实现Context:上下文类,是外界获取不同策略的接口二、策略模式利用2.1 Java Comparator中的策略模式在java.util.comparator 中,comparator作为比拟的接口,能够实现具体的比拟策略。而java.util.Collections 中的sort(List<T> list, Comparator<? super T> c) 作为context类,执行不同的比拟逻辑 能够做一个排序的demo来演示: public static void main(String[] args) { ArrayList<Integer> integers = new ArrayList<>(); integers.add(1); integers.add(3); integers.add(5); integers.add(4); integers.add(2); for (Integer integer : integers) { System.out.print(integer); } System.out.println("程序后~"); Collections.sort(integers,new AscComparator()); for (Integer integer : integers) { System.out.print(integer); } System.out.println("逆序后~"); Collections.sort(integers,new DescComparator()); for (Integer integer : integers) { System.out.print(integer); } InstantiationStrategy } static class DescComparator implements Comparator<Integer> { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } } static class AscComparator implements Comparator<Integer> { @Override public int compare(Integer o1, Integer o2) { return o1 - o2; } }最初输入: ...

September 8, 2023 · 2 min · jiezi

关于设计模式:浅析观察者模式在Java中的应用

观察者模式(Observer Design Pattern),也叫做公布订阅模式(Publish-Subscribe Design Pattern)、模型-视图(Model-View)模式、源-监听器(Source-Listener)模式、隶属者(Dependents)模式观察者模式利用最广的场景就是音讯公布订阅, 比方当零碎中实现一个业务事件, 须要告诉给不同的用户平台,这个时候就会有多种告诉形式,如: 那么就须要将音讯公布对象这一个状态的扭转, 告诉给另外多个平台的对象,像这种状况就适宜观察者模式。上面就具体的介绍一下观察者模式 一、观察者模式的介绍后面说到,观察者是一种行为设计模式,容许一个对象将其状态的扭转告诉其余对象。实际上次要的局部就是观察者和被观察者,比方前言提到的音讯公布,就属于被观察者,而各种不同的平台音讯揭示,则是一系列的观察者。那么观察者如何获取被观察者的状态变动呢?在观察者模式中是这样设计的: 1.1 观察者模式的构造在被观察者这一块,通过在被观察者中治理观察者,如add() 减少观察者,remove() 移除观察者和notifyObserver() 告诉/发送音讯给观察者等等办法,来达到告诉观察者,治理观察者数量的作用。在观察者这个角度,须要有response() 接管被观察者告诉的办法,来实现整个观察者模式的闭环。用UML图来展现则如下所示: 观察者模式构造中次要包含被观察者(Object)和观察者(Observer)两个构造: Subject:主题抽象类,提供一系列观察者对象,以及对这些对象的减少、删除和告诉的办法ConcreteSubject:主题具体实现类,实现形象主题中的告诉办法,告诉所有注册过的观察者对象Observer:观察者抽象类,蕴含一个告诉响应形象办法ConcreteObserver1、ConcreteObserver2:观察者实现类,实现形象观察者中的办法,以便在失去指标的更改告诉时更新本身的状态Client:客户端,对主题及观察者进行调用从下面的UML图咱们会晓得,通过形象观察者和被观察者,而后别离实现不同的观察者和被观察者,来达到将多个对象的不同状态传递给多个对象的作用。 1.2 观察者模式的实现依据下面的类图,咱们能够实现对应的代码。 首先定义一个形象指标类Subject,其中包含减少、登记和告诉观察者办法 public abstract class Subject { protected List<Observer> observerList = new ArrayList<Observer>(); /** * 减少观察者 * @param observer 观察者 */ public void add(Observer observer) { observerList.add(observer); } /** * 登记观察者,从观察者汇合中删除一个观察者 * @param observer 观察者 */ public void remove(Observer observer) { observerList.remove(observer); } /**告诉观察者*/ public abstract void notifyObserver();}对应具体的指标类ConcreteSubject ...

September 7, 2023 · 4 min · jiezi

关于设计模式:跟着-iLogtail-学习设计模式

设计模式是软件开发中的重要经验总结,Gang of Four (GoF) 提出的经典设计模式则被誉为设计模式中的“圣经”。然而设计模式往往是以形象和理论化的形式出现,对于初学者或者没有太多实战经验的开发者来说,间接学习设计模式往往会显得枯燥乏味。 市面上或者网上也常常有一些书籍或者文章,尝试以理论的利用场景深入浅出地介绍设计模式。然而这些材料所列举的样例或利用实际,往往都是一些结构的虚构场景,不足生产级软件的实在利用。而软件实践最重要的是学以致用,那是否有实在生产级代码的学习机会呢? iLogtail 作为一款阿里云日志服务(SLS)团队自研的可观测数据采集器,目前曾经在 Github 开源,其外围定位是帮忙开发者构建对立的数据采集层。iLogtail 在多年的技术演进过程中,也始终在尝试进行各种设计模式的利用,这些设计模式的利用大大晋升了软件的品质与可维护性。本文咱们将联合 iLogtail 我的项目,从实际角度探讨一些常见设计模式的技术原理。在这里也要感激字节跳动多位同学对 iLogtail Golang 局部架构的一些降级优化。 如果你已经感到学习设计模式枯燥无味,那么来学习 iLogtail 吧!欢送参加任何模式的社区探讨交换,置信你会发现学习设计模式也能够是一件十分乏味的事件! 创立型模式创立型模式的作用是提供一个通用的解决方案来创建对象,并暗藏创立的细节创建对象。说到创立一个对象,最相熟的就是 New 一个对象,而后设置相干属性。然而,在很多场景下,咱们须要给利用方提供更加敌对的创建对象的形式,尤其在创立各种简单类的场景下。 单例模式模式简介单例模式是指在整个零碎生命周期内,保障一个类只能产生一个实例,确保该类的唯一性。对于一些资源管理类的场景(例如配置管理),往往须要领有一个全局对象,这样有利于协调系统整体的行为。 iLogtail实际在 iLogtail 中,采集配置管理扮演着连接用户采集配置和外部采集工作的重要角色,通过加载与解析用户采集配置,建设具体的采集工作。 作为一个过程级的管理机制,ConfigManager 非常适合采纳单例模式。iLogtail 启动时会初始加载所有采集配置,并反对运行过程中动静加载变更的采集配置。通过单例模式,能够无效防止多个实例间状态同步的问题;也提供了对立的全局接口,不便各个模块进行调用。 class ConfigManager : public ConfigManagerBase {public: static ConfigManager* GetInstance() { static ConfigManager* ptr = new ConfigManager(); return ptr; }// 结构、析构、拷贝结构、赋值结构等均为公有,避免结构多个对象private: ConfigManager(); virtual ~ConfigManager(); ConfigManager(const ConfigManager&) = delete; ConfigManager& operator=(const ConfigManager&) = delete; ConfigManager(ConfigManager&&) = delete; ConfigManager& operator=(ConfigManager&&) = delete;};GetInstance() 函数是单例模式的要害,该函数内应用了动态变量、动态函数的形式,以确保在应用程序中只有一个 ConfigManager 类的实例。为了避免通过拷贝或赋值实例化多个 ConfigManager 对象,将拷贝构造函数和赋值运算符定义为公有,并将其标记为删除。 ...

September 6, 2023 · 3 min · jiezi

关于设计模式:装饰器模式让你的对象变得更强大

在日常开发中,当须要给一个现有类增加附加职责,而又不能采纳生成子类的办法进行裁减时。例如,该类被暗藏或者该类是终极类或者采纳继承形式会产生大量的子类。这时候,咱们该怎么办呢?咱们能够应用装璜器器模式来解决这个问题,本文将从以下四个方面解说装璜器器模式。 简介优缺点利用场景Java 代码示例、Spring 代码示例简介装璜器模式(Decorator Pattern)是一种结构型设计模式,它能够在不扭转现有对象的构造的状况下,动静地给对象减少一些额定的性能。装璜器模式通过创立一个包装对象(即装璜器)来包裹实在对象,并在放弃实在对象的接口不变的前提下,为其提供额定的性能。装璜器模式能够在运行时依据须要抉择不同的装璜器来组合和批改对象的行为。 Component(组件接口):所有被装璜组件及装璜器对应的接口标准,指定进行装璜的行为办法。对应本章例程中的展现接口 Showable。ConcreteComponent(组件实现):须要被装璜的组件,实现组件接口标准,只具备本身未被装璜的原始个性。对应本章例程中的女生类 Girl。Decorator(装璜器):装璜器的高层抽象类,同样实现组件接口标准,且蕴含一个被装璜的组件。ConcreteDecorator(装璜器实现):继承自装璜器抽象类的具体子类装璜器,能够有多种实现,在被装璜组件对象的根底上为其增加新的个性。对应本章例程中的粉底类 FoundationMakeup、口红类 Lipstick。举荐博主开源的 H5 商城我的项目waynboot-mall,这是一套全副开源的微商城我的项目,蕴含三个我的项目:经营后盾、H5 商城前台和服务端接口。实现了商城所需的首页展现、商品分类、商品详情、商品 sku、分词搜寻、购物车、结算下单、支付宝/微信领取、收单评论以及欠缺的后盾治理等一系列性能。 技术上基于最新得 Springboot3.0、jdk17,整合了 MySql、Redis、RabbitMQ、ElasticSearch 等罕用中间件。分模块设计、简洁易保护,欢送大家点个 star、关注博主。 github 地址:https://github.com/wayn111/waynboot-mall 优缺点装璜器模式的长处有: 装璜器模式是继承的无力补充,比继承灵便,在不扭转原有对象的状况下,动静地给一个对象扩大性能,即插即用。通过应用不同的装璜器及这些装璜器的排列组合,能够实现不同成果。装璜器模式齐全恪守开闭准则,能够在不批改原有代码的根底上减少新的性能。装璜器模式的毛病有: 装璜器模式会减少许多子类,适度应用会减少程序的复杂性。装璜器模式会减少对象之间的分割,可能会引入循环援用的问题。装璜器模式会影响对象的标识,当应用装璜器对对象进行包装时,对象的类型和行为可能会发生变化。利用场景装璜器模式实用于以下场景: 当须要给一个现有的类增加附加职责,而又不能采纳继承的形式时,能够应用装璜器模式。例如,在不批改原有代码的状况下给一个窗口增加滚动条或者边框等性能。当须要动静地给一个对象减少性能,而又须要撤销该性能时,能够应用装璜器模式。例如,在电子商务系统中依据用户抉择的不同优惠券来计算商品价格时,能够应用装璜器模式来实现。当须要为一批兄弟类进行改装或加装性能时,能够应用装璜器模式。例如,在一个图形界面工具箱中为多个不同的组件提供一些公共的性能时,能够应用装璜器模式来实现。java 代码示例以下是一个实现装璜器模式的 java 示例代码 定义了一个形象组件接口 Shape 和两个具体组件类 Circle 和 Rectangle,//形象组件接口public interface Shape { void draw();}//具体组件类:圆形public class Circle implements Shape { @Override public void draw() { System.out.println("Drawing a circle"); }}//具体组件类:矩形public class Rectangle implements Shape { @Override public void draw() { System.out.println("Drawing a rectangle"); }}定义一个形象装璜器类 ShapeDecorator 和两个具体装璜器类 RedShapeDecorator 和 GreenShapeDecorator,//形象装璜器类public abstract class ShapeDecorator implements Shape { //持有一个形象组件对象 protected Shape shape; //构造方法 public ShapeDecorator(Shape shape) { this.shape = shape; } //调用被包装对象的办法 @Override public void draw() { shape.draw(); }}//具体装璜器类:红色装璜器public class RedShapeDecorator extends ShapeDecorator { //构造方法 public RedShapeDecorator(Shape shape) { super(shape); } //重写draw办法,在调用被包装对象的办法之前或之后增加新的性能 @Override public void draw() { //调用被包装对象的办法 super.draw(); //增加新的性能 setRedBorder(); } //定义新的性能办法 private void setRedBorder() { System.out.println("Setting red border"); }}//具体装璜器类:绿色装璜器public class GreenShapeDecorator extends ShapeDecorator { //构造方法 public GreenShapeDecorator(Shape shape) { super(shape); } //重写draw办法,在调用被包装对象的办法之前或之后增加新的性能 @Override public void draw() { //调用被包装对象的办法 super.draw(); //增加新的性能 setGreenBorder(); } //定义新的性能办法 private void setGreenBorder() { System.out.println("Setting green border"); }}编写装璜器模式测试代码,main 函数中创立了不同的组件和装璜器对象,并调用了它们的办法,//测试类public class DecoratorPatternDemo { public static void main(String[] args) { //创立一个圆形对象 Shape circle = new Circle(); //创立一个矩形对象 Shape rectangle = new Rectangle(); //创立一个红色装璜器对象,包装圆形对象 Shape redCircle = new RedShapeDecorator(circle); //创立一个绿色装璜器对象,包装矩形对象 Shape greenRectangle = new GreenShapeDecorator(rectangle); //调用各个对象的办法,展现不同的成果 System.out.println("Normal circle:"); circle.draw(); System.out.println("Normal rectangle:"); rectangle.draw(); System.out.println("Red circle:"); redCircle.draw(); System.out.println("Green rectangle:"); greenRectangle.draw(); }}输入后果如下: ...

September 6, 2023 · 2 min · jiezi

关于设计模式:创建型设计模式建造者-Builder

简介建造者模式可将对象的初始化转变成一步步配置的过程。如当对象的初始化时有很多可选参数,建造者模式能够定制参数实现对象的创立。益处有: 定制对象参数针对不同参数,做不同的校验,如当设置了三角形的两个边长,设置第三个边时必须满足两边之和大于第三边的条件。角色Builder 类 定义建造一个Product分几个步骤 具体 Builder 类 实现不同的步骤 Director 属于疾速建造某一种产品的办法,如 Director 提供了创立自动挡和手动挡汽车两种办法,创立自动挡汽车中其实是调用 setA setB,而创立主动单汽车中调用setC setD。也能够不应用 Director,间接应用 Builder 的 setA setB 去设置属性 要被实例化的类 初始化时可定制的参数较多,如 setA setB setC... 类图图中的 Director 在 make 办法中封装了设置产品属性的步骤,通过传入不同的 builder 类,实现不同的实现步骤,创立不同的产品。 代码interface Builder{ public function producePartA(): void; public function producePartB(): void; public function producePartC(): void;}class ConcreteBuilder1 implements Builder{ private $product; public function __construct() { $this->reset(); } public function reset(): void { $this->product = new Product1(); } public function producePartA(): void { $this->product->parts[] = "PartA1"; } public function producePartB(): void { $this->product->parts[] = "PartB1"; } public function producePartC(): void { $this->product->parts[] = "PartC1"; } public function getProduct(): Product1 { $result = $this->product; $this->reset(); return $result; }}/** * EN: It makes sense to use the Builder pattern only when your products are * quite complex and require extensive configuration. * * Unlike in other creational patterns, different concrete builders can produce * unrelated products. In other words, results of various builders may not * always follow the same interface. * * RU: , * . * * , * . , * . */class Product1{ public $parts = []; public function listParts(): void { echo "Product parts: " . implode(', ', $this->parts) . "\n\n"; }}class Director{ private $builder; public function setBuilder(Builder $builder): void { $this->builder = $builder; } public function buildMinimalViableProduct(): void { $this->builder->producePartA(); } public function buildFullFeaturedProduct(): void { $this->builder->producePartA(); $this->builder->producePartB(); $this->builder->producePartC(); }}function clientCode(Director $director){ $builder = new ConcreteBuilder1(); $director->setBuilder($builder); echo "Standard basic product:\n"; $director->buildMinimalViableProduct(); $builder->getProduct()->listParts(); echo "Standard full featured product:\n"; $director->buildFullFeaturedProduct(); $builder->getProduct()->listParts(); // 不应用 Director,间接操作 builder 来创立产品 echo "Custom product:\n"; $builder->producePartA(); $builder->producePartC(); $builder->getProduct()->listParts();}$director = new Director();clientCode($director);output: ...

September 6, 2023 · 2 min · jiezi

关于设计模式:创建型设计模式抽象工厂-Abstract-Factory

简介拿工厂办法模式作比照,在工厂办法模式中,一个工厂只能创立一种产品,如椅子工厂只能创立椅子。而形象工厂能够创立一系列产品,如家具工厂能够创立椅子,桌子,床等等。 形象工厂类负责定义能够创立的形象产品类,具体工厂编写不同格调(即各自的业务逻辑)的创立产品的过程。 角色形象工厂 定义工厂能够生产的形象产品,多个产品则对应多个创立办法 形象产品 与工厂办法模式中没什么区别,简略定义类属性即可 可能有多个,形象椅子,形象桌子,形象床等 具体工厂 别离实现形象工厂中定义的创立产品的办法 可能有多个,依照不同格调或叫不同业务逻辑,创立一组产品,如古典工厂创立古典风格椅子、桌子、床,古代工厂创立古代格调桌椅床。 具体产品 实现形象产品即可 可能有多个,古代格调桌子、古典风格椅子等等 类图图中展现,GUIFactory 形象工厂定义能够创立 Button 和 Checkbox 形象产品。 具体工厂WinFactory能够创立出 Win 格调的 WinButton 和 WinCheckbox,MacFatory 能够创立出 Mac 格调的 MacButton 和 MacCheckbox。 代码interface AbstractFactory{ public function createProductA(): AbstractProductA; public function createProductB(): AbstractProductB;}class ConcreteFactory1 implements AbstractFactory{ public function createProductA(): AbstractProductA { return new ConcreteProductA1(); } public function createProductB(): AbstractProductB { return new ConcreteProductB1(); }}class ConcreteFactory2 implements AbstractFactory{ public function createProductA(): AbstractProductA { return new ConcreteProductA2(); } public function createProductB(): AbstractProductB { return new ConcreteProductB2(); }}interface AbstractProductA{ public function usefulFunctionA(): string;}class ConcreteProductA1 implements AbstractProductA{ public function usefulFunctionA(): string { return "The result of the product A1."; }}class ConcreteProductA2 implements AbstractProductA{ public function usefulFunctionA(): string { return "The result of the product A2."; }}interface AbstractProductB{ public function usefulFunctionB(): string; public function anotherUsefulFunctionB(AbstractProductA $collaborator): string;}class ConcreteProductB1 implements AbstractProductB{ public function usefulFunctionB(): string { return "The result of the product B1."; } public function anotherUsefulFunctionB(AbstractProductA $collaborator): string { $result = $collaborator->usefulFunctionA(); return "The result of the B1 collaborating with the ({$result})"; }}class ConcreteProductB2 implements AbstractProductB{ public function usefulFunctionB(): string { return "The result of the product B2."; } public function anotherUsefulFunctionB(AbstractProductA $collaborator): string { $result = $collaborator->usefulFunctionA(); return "The result of the B2 collaborating with the ({$result})"; }}function clientCode(AbstractFactory $factory){ $productA = $factory->createProductA(); $productB = $factory->createProductB(); echo $productB->usefulFunctionB() . "\n"; echo $productB->anotherUsefulFunctionB($productA) . "\n";}echo "Client: Testing client code with the first factory type:\n";clientCode(new ConcreteFactory1());echo "Client: Testing the same client code with the second factory type:\n";clientCode(new ConcreteFactory2());output: ...

September 6, 2023 · 2 min · jiezi

关于设计模式:创建型设计模式工厂方法-Factory-Method

简介工厂办法中,每一个具体工厂类都对应创立一个具体产品类,所有具体工厂类都实现形象工厂,所有具体产品类都实现形象产品。 形象工厂定义了创立形象产品的办法签名,具体工厂类各自实现各自逻辑,来创立具体的产品。 角色形象工厂 Abstract Factory 定义创立产品的办法签名,即Factory Method 形象产品 Abstract Product 定义产品的根本属性 具体工厂 Concrete Factory 实现自形象工厂,并实现 Factory Method,实现如何创立具体产品。 具体产品 Concrete Product 实现具体产品根本属性 类图如图所示,Dialog形象工厂能够创立Button形象产品,WindowsDialog和WebDialog都是具体工厂,负责创立WindownsButton和HTMLButton。 代码abstract class Creator{ abstract public function factoryMethod(): Product; public function someOperation(): string { $product = $this->factoryMethod(); $result = "Creator: The same creator's code has just worked with " . $product->operation(); return $result; }}class ConcreteCreator1 extends Creator{ public function factoryMethod(): Product { return new ConcreteProduct1(); }}class ConcreteCreator2 extends Creator{ public function factoryMethod(): Product { return new ConcreteProduct2(); }}interface Product{ public function operation(): string;}class ConcreteProduct1 implements Product{ public function operation(): string { return "{Result of the ConcreteProduct1}"; }}class ConcreteProduct2 implements Product{ public function operation(): string { return "{Result of the ConcreteProduct2}"; }}function clientCode(Creator $creator){ echo "Client: I'm not aware of the creator's class, but it still works.\n" . $creator->someOperation() . "\n";}echo "App: Launched with the ConcreteCreator1.\n";clientCode(new ConcreteCreator1());echo "App: Launched with the ConcreteCreator2.\n";clientCode(new ConcreteCreator2());output ...

September 6, 2023 · 1 min · jiezi

关于设计模式:从设计模式谈业务开发

一、背景前台业务同学在业务承接过程中总是埋怨大部分业务无奈通过设计模式来承接,写的代码是越来越没有谋求,理由是我无奈预测将来的业务的倒退,且设计模式更多的是在框架或中间件中应用。然而设计模式是对能力形象出的通用模式,从哲学的角度来看世间万物皆尘土,事物都是能够形象出独特的实质的货色。所以,难道只有底层能力能够形象,业务逻辑局部就不能够形象了?必须能够才是啊。在前台业务承接过程中除了能力能够形象,还有能够形象出业务流程,假如在有这样一些业务场景,品搜和图搜、直播间评论和点赞、公域直播会场和私域商详透直播等等,这些各畛域内的业务流程“大同小异”,因而都能够形象出通用的业务流程节点。然而通常在一个骨干流程须要承接的场景有很多,比方直播间互动这个骨干流程包含了直播间评论、点赞、求解说、看证书、进场等等场景,所以咱们须要通过次要流程进行进行多场景承接。然而这样还不够,在面对多端型多场景的状况下须要解决返回不同的数据模型。综上所述,咱们如何通过一个骨干业务流程承接多个业务场景并在数据上可适配到多端型多场景,实现在服务端高质量高效率的“包接口”,上面会具体介绍。 二、业务承接如果你面临的问题是在同一个业务域上承接多种相似的业务场景,每天在适配各种端型或者各种场景而对外提供接口时,为了保障利用零碎的可扩展性和高效承接业务,那么能够依照如下步骤进行设计。 2.1 业务流程形象首先须要进行业务建模,形象出用户用例或者user story,当然具体的粒度能够本人把控,具体如下: 2.1.1 用户用例在直播间互动畛域内的用户用例如下: 从整个零碎登程,挖掘出面向不同的用户提供的能力有哪些,在这些用例背地须要进行的流程和节点又是什么。通过这些流程和节点能力进行后续的零碎时序和流程形象,举例如下 在互动畛域内的流程和节点如下: 风控查看评论长久化评论上屏评论进沟通2.2.2 零碎时序基于用户用例进行剖析,这些用例都须要通过什么的流程节点进行解决,而后将这些流程依照零碎时序进行出现。 到此基于上述的用例和时序是不是能够形象出具体互动流程了,不言而喻。 2.2.3 业务流程形象有了零碎用例和零碎时序这一步就比较简单,从零碎时序里很容易能够形象出具体的流程和流程中的解决节点,具体如下: 对于直播间互动畛域能够形象出的业务流程:风控查看->互动内容长久化-》音讯上屏-》互动进IM对于直播间散发畛域能够形象出的业务流程:直播举荐-》直播间根底信息-》直播流信息-》直播间品信息到此,大家能够依照上述步骤在大脑里对本人的业务域进行形象进去了。 2.2.4 设计模式固化主流程依照业务主流程能够通过模板模式将解决流程固定下来,如下所示: @Override@LiveLog(logResult = true)public InteractionResult interactionSubmit(MobileInteractionRequest request, InteractionLiveRoom liveRoom) { Boolean needSave = MapUtils.getBoolean(request.getExtInfo(), LiveInteractionConstant.NEED_SAVE); // 默认保留 InteractionResult saveResult = null; if (Objects.isNull(request.getExtInfo()) || Objects.isNull(needSave) || needSave) { saveResult = save(request, liveRoom); if(Objects.nonNull(saveResult) && !saveResult.isSuccess()) { return saveResult; } } // 默认进沟通 InteractionResult chatResult; if (Objects.isNull(request.getSendToChat()) || Boolean.parseBoolean(request.getSendToChat())) { chatResult = sendToChat(request); if(Objects.nonNull(chatResult) && !chatResult.isSuccess()) { return chatResult; } } if(Objects.nonNull(saveResult) && saveResult.isSuccess()) { return saveResult; } return null;}/** * 互动行为保留到数据库或者缓存中 * * @param request * @return */protected abstract InteractionResult save(MobileInteractionRequest request, InteractionLiveRoom liveRoom);/** * 进沟通 * * @param request * @return */protected abstract InteractionResult sendToChat(MobileInteractionRequest request);2.2 业务流程扩大因在上述模版模式中预留了两个扩大点,所以在子类中能够通过扩大点进行扩大,举例如下: ...

July 6, 2023 · 3 min · jiezi

关于设计模式:设计模式之组合模式企业部门的结构

前言本文次要讲述组合模式,文中应用通俗易懂的案例,使你更好的学习本章知识点并了解原理,做到有道无术。 一.什么是组合模式组合模式是23种设计模式中结构型模式的一种,它创立了对象组的树形构造,将对象组合成树形构造以示意“局部-整体”的层次结构。组合模式使得用户对单个对象和组合对象的应用具备一致性。 二.生存中的组合模式1.文件夹 在咱们的电脑外面会存在很多材料,不论是学习材料、工作材料还是各种游戏。咱们都不会抉择一股脑地都放在一个盘下,而是会进行分门别类。比方江帅的电脑, D 盘里有个目录为 workspace 外面会寄存各种代码, Program Files 会寄存各种装置软件,game 外面会寄存各种游戏,这样就能不便咱们治理硬盘里内容,而这种分类形式就跟组合模式一样。 2.企业治理 在各个企业里都会有不同的部门以及不同级别的领导,比方级别最高是 CEO (首席执行官)和 CTO (首席技术官)等等,在之下有各部门的总监,副总监,之后是部长和各部门的主管,最初才是基层员工和实习生,而这种分类可能让企业治理起来更加地高效,这种治理形式就跟组合模式一样。 3.军队治理 目前在中国的军队中,军衔分为2等10级,如此划分不仅仅只是能力跟待遇的区别,也是为了更好的进行军队治理,而这种治理形式就跟组合模式一样。 三.组合模式的实现接下来咱们以所在的公司来举例,通过组合模式来实现。公司里有多个职能核心,每个职能核心中有一个或者多个部门。 首先咱们先创立一个形象构件(Component)角色 package com.qianfeng.ran;/* * @author:江帅 * 形象构建角色 */public abstract class Component { //名称 private String name; //职责 private String responsibility; public Component(String name, String responsibility) { this.name = name; this.responsibility = responsibility; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getResponsibility() { return responsibility; } public void setResponsibility(String responsibility) { this.responsibility = responsibility; } /** * 默认实现 * @param component */ protected void add(Component component) { throw new UnsupportedOperationException("该办法不反对"); } protected void remove(Component component) { throw new UnsupportedOperationException("该办法不反对"); } /** * 打印办法 */ protected abstract void print();}而后创立两个树枝构件角色公司类和组织类 ...

June 30, 2023 · 2 min · jiezi

关于设计模式:设计模式代码质量评价标准和设计原则

1、代码品质评估规范可维护性(maintainability) “代码易保护”就是指,在不毁坏原有代码设计、不引入新的 bug 的状况下,可能疾速地批改或者增加代码。 “代码不易保护”就是指,批改或者增加代码须要冒着极大的引入新 bug 的危险,并且须要破费很长的工夫能力实现。 可读性(readability) 任何傻瓜都会编写计算机能了解的代码。好的程序员可能编写人可能了解的代码。 可扩展性(extensibility) 代码的可扩展性示意,咱们在不批改或大量批改原有代码的状况下,通过扩大的形式增加新的性能代码。 灵活性(flexibility) 如果一段代码易扩大、易复用或者易用,咱们都能够称这段代码写得比拟灵便。 简洁性(simplicity) 尽量放弃代码简略。代码简略、逻辑清晰,也就意味着易读、易保护。咱们在编写代码的时候,往往也会把简略、清晰放到首位。 可复用性(reusability) 尽量减少反复代码的编写,复用已有的代码。 可测试性(testability) 代码可测试性的好坏,能从侧面上十分精确地反馈代码品质的好坏。代码的可测试性差,比拟难写单元测试,那基本上就能阐明代码设计得有问题。 其中比拟罕用的三个规范是:可维护性、可读性、可扩展性。 2、设计准则SRP 繁多职责准则 一个类或者模块只负责实现一个职责(或者性能) OCP 开闭准则 软件实体(模块、类、办法等)应该“对扩大凋谢、对批改敞开”。 LSP 里式替换准则 子类对象(object of subtype/derived class)可能替换程序(program)中父类对象(object of base/parent class)呈现的任何中央,并且保障原来程序的逻辑行为(behavior)不变及正确性不被毁坏。子类在设计的时候,要恪守父类的行为约定(或者叫协定)。父类定义了函数的行为约定,那子类能够扭转函数的外部实现逻辑,但不能扭转函数原有的行为约定。这里的行为约定包含:函数申明要实现的性能;对输出、输入、异样的约定;甚至包含正文中所列举的任何非凡阐明。ISP 接口隔离准则 客户端不应该被强制依赖它不须要的接口。其中的“客户端”,能够了解为接口的调用者或者使用者。 DIP 依赖倒置准则 高层模块(high-level modules)不要依赖低层模块(low-level)。高层模块和低层模块应该通过形象(abstractions)来相互依赖。除此之外,形象(abstractions)不要依赖具体实现细节(details),具体实现细节(details)依赖形象(abstractions)。 DRY 准则、KISS 准则、YAGNI 准则、LOD 法令 DRY 不要写反复的代码。 KISS 尽量放弃简略 YAGNI 不要去设计以后用不到的性能;不要去编写以后用不到的代码。核心思想就是:不要做适度设计。 LOD 不该有间接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。

June 28, 2023 · 1 min · jiezi

关于设计模式:快速掌握前端必会的-7-种设计模式轮台东门送君去

download:疾速把握前端必会的 7 种设计模式水波成果的事实:摸索颗粒零碎的利用 H1:引言 水波成果是计算机图形学中常见的视觉效果之一,足以为场景减少动静和实在感触。在本文中,咱们将深入探讨应用颗粒零碎来实现水波效率的办法。颗粒零碎是一种模仿颗粒行为的技术,通过模仿水波的波能源过程,使场景中的水面看起来像生的一样。咱们将具体介绍事实水波成果的根底原理和具体步骤,并探讨该技术在游戏开发、虚拟现实和可视化利用中的潜在利用。 H1:水波效应的根底原理 水波成果的基本原理是模仿水面上波浪的形态和流传过程。波浪通常由颗粒的振动和传引引起。颗粒在水面上受到到外力的作用,如风力、物体的撞击等,从而引发振动。这些振动通过颗粒之间的相互作用和传递,造成波浪成果。在事实水波无效时,咱们须要模仿颗粒的静止和相互作用,以及将这些信息利用到场景中的水面上。 H1:事实水波成果的步骤 理论水波成果的根本步骤如下: 颗粒的生成:首先,咱们须要生成一组颗粒,用于模仿水面上的振动。这些颗粒能够是在水面上平均分配的点,或者能够依据特定的状态生成,如圆形或石形。 颗粒的静止模仿:接下来,咱们须要模仿颗粒的静止过程。每个颗粒依据其初始地位和外力的作用,如风力或物体的撞击,进行静止。通过对颗粒施力和计算速度、速度等物理性质,能够模仿颗粒的振动和静止。 颗粒的相互作用:颗粒之间的相互作用是造成波浪成果的要害。咱们能够应用一些物理模型,如弹弓-质点模型,来模仿颗粒之间的弹性连贯。通过计算与邻颗粒之间的间隔和施力,能够实现颗粒之间的相互作用。 波浪的播送:一颗旦粒的静止和相互作用被模仿进去,咱们能够将这些信息利用到场景中的水面上

May 26, 2023 · 1 min · jiezi

关于设计模式:Go设计模式之工厂模式

工厂模式属于结构型模式,能够细分为三种模式: 简略工厂模式工厂办法模式形象工厂模式这三种模式从上到下逐渐形象,在学习工厂模式之前,须要先明确为什么要应用工厂模式。工厂模式对类的实例化过程进行了形象,可能将软件模块中对象的创立和对象的应用拆散。为了能使得代码构造和逻辑更加清晰,外界对于这些对象只须要晓得他们独特的接口,而不须要晓得外部具体的实现逻辑,使得整个零碎的设计更加合乎繁多指摘准则。工厂模式代替new初始化实例对象,这样做的益处是封装了更多的实现细节,能够对对象的生命周期进行更好的治理。 一、简略工厂模式简略工厂模式是三种模式中最简略的模式、也是最罕用的一种工厂模式。简略工厂模式时有一个工厂来决定创立哪一种实例对象。代码如下: package factoryimport "fmt"type Phone interface { Show()}// ----------实现层逻辑------------type Apple struct { Phone}func (a *Apple) Show() { fmt.Println("苹果手机")}type Huawei struct { Phone}func (h *Huawei) Show() { fmt.Println("华为手机")}type Xiaomi struct { Phone}func (x *Xiaomi) Show() { fmt.Println("小米手机")}// ----------工厂模块------------type Factory struct {}func (f *Factory) createFruit(kind string) Phone { var phone Phone switch kind { case "apple": phone = new(Apple) case "huawei": phone = new(Huawei) case "xiaomi": phone = new(Xiaomi) } return phone}测试用例 ...

May 18, 2023 · 3 min · jiezi

关于设计模式:设计模式的使用套路

设计模式的应用套路简介是什么设计模式是针对软件开发中常常遇到的一些设计问题,演绎进去的一套实用的解决方案或者设计思路。 局限性设计模式自身是经验性的演绎,归纳法自身便容易产生对法则不齐全演绎的状况。 每种设计模式是特定场景下较优的解决方案,不是语法规定,没有对与错,只有合不适合或者好与不好。 作用边界作用成果复用性✅可维护性✅可读性✅稳健性✅安全性✅运行效率❌难点什么时候用,怎么用,该不该用 先说论断不须要拿着23种设计模式往代码上套,而是应该在须要组织形象、解耦构造时,像查字典一样查找须要应用的设计模式。 代码设计流程如下,次要关注虚线框中【查阅设计模式】的局部 实现问题的形式规范的软件开发中,性能实现局部次要流程是 需要剖析->总体设计->具体设计->代码实现,但具体到一个办法,应如何套用这套流程? 自底向上和自顶向下同样实现一项工作,通常有自底向上和自顶向下两种办法,以实现斐波那契数列为例(f(n) = f(n-1) + f(n-2)): 自底向上 function fib(n) { let pprev = 1; let prev = 1; if(n<=2) return 1 for(let i=2; i<n; i++) { const oldPprev = pprev; pprev = prev; prev = pprev + oldPprev; } return pprev + prev}自顶向上 // 缓存装璜器办法// js中的装璜器写法可参考: https://es6.ruanyifeng.com/#docs/decoratorfunction cache(fn) { const cache = {} const proxyFunc = (n) => { if(n in cache) return cache[n]; const rst = fn(n); cache[n] = rst; return rst; } this[fn.name] = proxyFunc; return proxyFunc;}// 次要代码@cachefunction fib(n) { if(n<3) return 1; return fib(n-1)+fib(n-2)}仅看此案例,自底向上的写法或者更清晰,且空间复杂度更低。 ...

May 6, 2023 · 2 min · jiezi

关于设计模式:设计模式-建造者模式

建造者模式是一种对象创立型模式,它将客户端与蕴含多个部件的简单对象的创立过程拆散,客户端毋庸晓得简单对象的外部组成部分与拆卸形式,只须要晓得所需建造者的类型即可。建造者模式关注如何逐渐创立一个简单的对象,不同的建造者定义了不同的创立过程,且具体建造者互相独立,且更换建造者和减少建造者十分的不便,零碎具备较好的扩展性。1 | 建造者模式概述无论是在事实世界中还是软件系统中,都存在一些简单的对象,他们领有多个组成部分(部件),例如汽车,它包含车轮、方向盘、发动机等多种部件。对于大多数用户而言,并不知道这些部件的拆卸细节,也简直不会应用独自某个部件,而是应用一辆残缺的汽车。思考:面对下面这种场景,如何将这些部件组装成一辆残缺的汽车并返回给用户,而这种场景恰好就是建造者模式须要解决的问题。建造者模式能够将部件自身和它们的组装过程离开,关注如何一步步创立一个蕴含多个组成部分的简单对象,用户只须要指定简单对象的类型即可失去该对象,而无需晓得其外部的具体构建细节。 1.1 建造者模式的定义• 建造者模式:将一个简单对象的构建与它的示意拆散,使得同样的构建过程能够创立不同的示意。• Builder Pattern: Separate the construction of a complex object from its representation so that the same construction process can create different representations.建造者模式是一种对象创立型模式,它将客户端与蕴含多个部件的简单对象的创立过程拆散,客户端毋庸晓得简单对象的外部组成部分与拆卸形式,只须要晓得所需建造者的类型即可。建造者模式关注如何逐渐创立一个简单的对象,不同的建造者定义了不同的创立过程,且具体建造者互相独立,且更换建造者和减少建造者十分的不便,零碎具备较好的扩展性。 2 | 建造者模式的构造与实现2.1 建造者模式的构造• (1) Builder(形象建造者):它为创立一个产品 Product 对象的各个部件指定形象接口,在该接口中个别申明两类办法,一类办法是 BuildPartX() (例如图6-2中的 BuildPartA()、BuildPartB() 等),它们用于创立简单对象的各个部件;另一类办法是GetResult(),它们用于返回简单对象。Builder既能够是抽象类,也能够是接口。• (2) ConcreteBuilder(具体建造者):它实现了 Builder 接口,实现各个部件的具体结构和拆卸办法,定义并明确所创立的简单对象,还能够提供一个办法返回创立好的简单产品对象(该办法也可由形象建造者实现)。• (3) Product(产品):它是被构建的简单对象,蕴含多个组成部件,具体建造者创立该产品的外部示意并定义它的拆卸过程。• (4) Director(指挥者):指挥者又称为导演类,它负责安顿简单对象的建造秩序,指挥者与形象建造者之间存在关联关系,能够在其 Construct() 建造办法中调用建造者对象的部件结构与拆卸办法,实现简单对象的建造。客户端个别只须要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也能够通过配置文件和反射机制),而后通过指挥者类的构造函数或者 Setter 办法将该对象传入指挥者类中。 2.2 建造者模式的实现在构建模式的定义中提到了简单对象,那什么是简单对象呢?简略来说,简单对象是指蕴含多个成员变量的对象,这些成员对象也称为部件或整机。举例:• 汽车(简单对象)包含:方向盘,车灯,发动机,轮胎,座椅等部件;• 电子邮件(简单对象)包含:发件人,收件人,主题,内容、附件等部件;建造者模式的代码设计 using System;namespace BuilderPattern{ class Program { static void Main(string[] args) { Console.WriteLine("Hello BuilderPattern!"); { Builder builder = new ConcreteBuilder1(); Director director = new Director(builder); Product product = director.Construct(); //构建简单对象 Console.WriteLine($"【简单对象】=> PartA:{product.PartA},PartB:{product.PartB},PartC:{product.PartC}"); } } } #region BuilderPattern-Demo /// <summary> /// 产品 /// </summary> class Product { public string PartA { get; set; } public string PartB { get; set; } public string PartC { get; set; } } /// <summary> /// 构建着 & 抽象类 /// </summary> abstract class Builder { //创立产品对象 protected readonly Product product = new Product(); public abstract void BuildPartA(); public abstract void BuildPartB(); public abstract void BuildPartC(); /// <summary> /// 返回产品对象 /// </summary> /// <returns></returns> public Product GetResult() { return product; } } /// <summary> /// 具体构建者 /// </summary> class ConcreteBuilder1 : Builder { public override void BuildPartA() { product.PartA = "A1"; } public override void BuildPartB() { product.PartB = "B1"; } public override void BuildPartC() { product.PartC = "C1"; } } /// <summary> /// 指挥者 /// </summary> class Director { private Builder _builder; public Director(Builder builder) { _builder = builder; } public void SetBuilder(Builder builder) { _builder = builder; } /// <summary> /// 产品构建与组装办法 /// </summary> /// <returns></returns> public Product Construct() { _builder.BuildPartA(); _builder.BuildPartB(); _builder.BuildPartC(); return _builder.GetResult(); } } #endregion}在指挥者类中能够注入一个形象建造者类型的对象,它提供了一个建造者办法 Construct() ,在该办法中调用了 builder 对象的结构部件的办法,最初返回一个产品对象。 ...

April 19, 2023 · 2 min · jiezi

关于设计模式:设计模式入门

1、结构器模式对于结构器模式,是如果有一个对象波及到多个参数须要设置的时候,能够应用结构器模式来构建外面的元素 比方有三个对象:参考dolpinscheduler中的概念流程定义流程实例工作实例 当初的需要是将三者封装成一个工作从Master传递到Worker,此时就能够应用结构器模式比方构建一个TaskContext,其中蕴含了以上对象中的元素而后应用一个构建一个TaskRequest应用结构器模式来构建对象 public class TaskRequest { private TaskContext taskContext = new TaskContext(); /** * 构建TaskRequest * @return */ public static TaskRequest newBuilder() { return new TaskRequest(); } /** * 设置工作相干信息 * @param task * @return */ public TaskRequest setTask(Task task) { taskContext.setTaskName(task.getTaskName()); taskContext.setTaskType(task.getTaskType()); return this; } /** * 设置流程实例相干信息 * @param processInstance * @return */ public TaskRequest setProcessInstance(ProcessInstance processInstance) { taskContext.setExecuteUser(processInstance.getExecuteUser()); taskContext.setStartTime(processInstance.getStartTime()); taskContext.setEndTime(processInstance.getEndTime()); return this; } /** * 设置流程定义相干信息 * @param processDefinition * @return */ public TaskRequest setProcessDefinition(ProcessDefinition processDefinition) { taskContext.setProjectName(processDefinition.getProjectName()); return this; } /** * 获取工作上下文 * @return */ public TaskContext build() { return taskContext; }}2、组合模式 + 访问者模式对于树形构造的id,pid模式的就能够应用组合模式 + 访问者模式 ...

April 2, 2023 · 9 min · jiezi

关于设计模式:设计模式策略模式

前言作为一名合格的前端开发工程师,全面的把握面向对象的设计思维十分重要,而“设计模式”是泛滥软件开发人员通过相当长的一段时间的试验和谬误总结进去的,代表了面向对象设计思维的最佳实际。正如《HeadFirst设计模式》中说的一句话,十分好: 晓得形象、继承、多态这些概念,并不会马上让你变成好的面向对象设计者。设计巨匠关怀的是建设弹性的设计,能够保护,能够应酬扭转。是的,很多时候咱们会感觉本人曾经分明的把握了面向对象的基本概念,封装、继承、多态都能纯熟应用,然而零碎一旦简单了,就无奈设计一个可保护、弹性的零碎。本文将联合 《HeadFirst设计模式》书中的示例加上本人一丢丢的集体了解,带大家意识下设计模式中的第一个模式——策略模式。 策略模式策略模式:Strategy,是指,定义一组算法,并把其封装到一个对象中。而后在运行时,能够灵便的应用其中的一个算法模仿鸭子游戏设计模仿鸭子游戏一个游戏公司开发了一款模仿鸭子的游戏,所有的鸭子都会呱呱叫(quack)、游泳(swim) 和 显示(dislay) 办法。 基于面向对象的设计思维,想到的是设计一个 Duck 基类,而后让所有的鸭子都集成此基类。 class Duck { quack() { } swim() { } display() { }}绿头鸭(MallardDuck)和红头鸭(RedheadDuck)别离继承 Duck 类: class MallardDuck extends Duck { quack() { console.log('gua gua'); } display() { console.log('I am MallardDuck'); }}class RedheadDuck extends Duck { display() { console.log('I am ReadheadDuck'); } quack() { console.log('gua gua'); }}让所有的鸭子会飞当初对所有鸭子提出了新的需要,要求所有鸭子都会飞。 设计者立马想到的是给 Duck 类增加 fly 办法,这样所有的鸭子都具备了航行的能力。 class Duck { quack() { } fly() { } swim() { } display() { }}然而这个时候代码通过测试发现了一个问题,零碎中新加的橡皮鸭(RubberDuck)也具备了航行的能力了。这显然是不迷信的,橡皮鸭不会飞,而且也不会叫,只会收回“吱吱”声。 ...

March 4, 2023 · 3 min · jiezi

关于设计模式:迭代器模式-Iterator

迭代器模式(Iterator Pattern)是一种行为设计模式,它容许客户端依照特定的形式遍历汇合中的元素,而无需裸露汇合的内部结构。 上面是一个应用 TypeScript 实现的迭代器模式的示例代码: interface Iterator<T> { next(): T; hasNext(): boolean;}class MyArray<T> { private elements: T[]; constructor() { this.elements = []; } add(element: T) { this.elements.push(element); } getIterator(): Iterator<T> { return new ArrayIterator(this.elements); }}class ArrayIterator<T> implements Iterator<T> { private index: number; private readonly elements: T[]; constructor(elements: T[]) { this.index = 0; this.elements = elements; } hasNext(): boolean { return this.index < this.elements.length; } next(): T { if (this.hasNext()) { const element = this.elements[this.index]; this.index++; return element; } return null; }}// Example usage:const myArray = new MyArray<number>();myArray.add(1);myArray.add(2);myArray.add(3);const iterator = myArray.getIterator();while (iterator.hasNext()) { console.log(iterator.next()); // Output: 1, 2, 3}在下面的示例中,MyArray 类示意一个数组,它蕴含一个 getIterator 办法,该办法返回一个迭代器对象。ArrayIterator 类是迭代器的具体实现,它实现了 Iterator 接口中定义的 next 和 hasNext 办法。在 next 办法中,咱们首先查看是否有下一个元素,如果有则返回以后元素,并将索引向前挪动。在 hasNext 办法中,咱们查看以后索引是否小于数组的长度,如果是,则返回 true,否则返回 false。 ...

February 19, 2023 · 2 min · jiezi

关于设计模式:解释器模式-Interpreter

解释器模式是一种行为型设计模式,其目标是定义语言的文法,并且应用该语法来解释输出的表达式。上面是一个应用 TypeScript 实现的解释器模式的示例: 假如咱们须要计算一个简略的算术表达式(加、减、乘、除),咱们能够应用解释器模式来解决这个问题。 首先,咱们须要定义一个形象表达式类 Expression,它有一个形象办法 interpret(): abstract class Expression { public abstract interpret(): number;}而后,咱们定义具体的表达式类,例如 NumberExpression、AddExpression、SubstractExpression、MultiplyExpression 和 DivideExpression,它们都是 Expression 的子类,实现了 interpret() 办法。其中,NumberExpression 示意一个数字,其 interpret() 办法返回该数字;AddExpression 示意一个加法表达式,其 interpret() 办法返回两个表达式的和,以此类推。 class NumberExpression extends Expression { constructor(private value: number) { super(); } public interpret(): number { return this.value; }}class AddExpression extends Expression { constructor(private left: Expression, private right: Expression) { super(); } public interpret(): number { return this.left.interpret() + this.right.interpret(); }}class SubtractExpression extends Expression { constructor(private left: Expression, private right: Expression) { super(); } public interpret(): number { return this.left.interpret() - this.right.interpret(); }}class MultiplyExpression extends Expression { constructor(private left: Expression, private right: Expression) { super(); } public interpret(): number { return this.left.interpret() * this.right.interpret(); }}class DivideExpression extends Expression { constructor(private left: Expression, private right: Expression) { super(); } public interpret(): number { return this.left.interpret() / this.right.interpret(); }}最初,咱们定义一个 Calculator 类,它蕴含一个 Expression 对象,并提供一个 calculate() 办法,应用该对象对表达式进行解释和计算: ...

February 19, 2023 · 1 min · jiezi

关于设计模式:设计模式

"设计模式" (Design Patterns) 是软件工程中的一种解决方案的通用办法。它们提供了一种可重复使用的办法来解决软件开发中的常见问题。设计模式通常是由经验丰富的软件工程师提出的,并在大量我的项目中进行了实践证明。 一共有 23 种常见的设计模式,它们分为三个类别:创立型模式、结构型模式和行为型模式。 创立型模式: 单例模式 (Singleton)工厂模式 (Factory)形象工厂模式 (Abstract Factory)建造者模式 (Builder)原型模式 (Prototype)结构型模式: 适配器模式 (Adapter)桥接模式 (Bridge)组合模式 (Composite)装璜器模式 (Decorator)外观模式 (Facade)享元模式 (Flyweight)代理模式 (Proxy)结构型模式: 责任链模式 (Chain of Responsibility)命令模式 (Command)解释器模式 (Interpreter)迭代器模式 (Iterator)中介者模式 (Mediator)备忘录模式 (Memento)观察者模式 (Observer)状态模式 (State)策略模式 (Strategy)模板办法模式 (Template Method)访问者模式 (Visitor)单例模式 (Singleton)单例模式是一种罕用的设计模式,该模式确保一个类只有一个实例,并且提供了一个全局的拜访点来拜访该实例。实现单例模式的办法: // 单例模式的外围代码class Singleton { static instance = null; static getInstance() { if (Singleton.instance === null) { Singleton.instance = new Singleton(); } return Singleton.instance; }}// 应用单例模式const instance1 = Singleton.getInstance();const instance2 = Singleton.getInstance();console.log(instance1 === instance2); // 输入:true理论场景代码示例: ...

February 13, 2023 · 2 min · jiezi

关于设计模式:短小精悍的发布订阅库-mitt

介绍mitt 是一个小而美的公布-订阅库,短短的几十行代码,小于 200b 的体积,提供三个重要的 API。然而麻雀虽小,五脏俱全。 公布-订阅模式公布-订阅模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象。这个主题对象在本身状态变动时,会告诉所有订阅者对象,使它们可能自动更新本人的状态。 用法有这样的一个需要,小明想买 100w 以内的二手房,小华想买 150w 左右的二手房,然而房产中介通知他俩,临时没有他们想要的房源,中介的工作人员留下他俩的联系方式,一旦有适合的房源就通过电话告诉。这就是一个经典应用公布-订阅的模式的场景。请看上面的代码。 const mitt = require("mitt");const houseAgents = mitt();houseAgents.on("xiaoming", () => { console.log("有 100w 以内的房源了");});houseAgents.on("xiaohua", () => { console.log("有 150w 左右的房源了");});过了一段时间,中介收到 150w 左右的房源,立马告诉 xiaohua。 houseAgents.emit("xiaohua");源码剖析mitt 通过几十行代码实现了公布-订阅机制。咱们来分析一下 mitt 源码。 function mitt(all) { all = all || Object.create(null); return { on: function () { /* some code*/ }, emit: function () { /* some code*/ }, off: function () { /* some code*/ }, };}mitt 库的源码中只有一个 mitt 函数。它接管 all 参数,返回一个对象,该对象蕴含 on、emit、off 三个办法。 ...

February 13, 2023 · 2 min · jiezi

关于设计模式:15分钟入门23种设计模式图解范例和对比

本文力求在15分钟内,通过范例和类比,让你对面向对象的23种设计模式造成提纲挈领的意识,从而让咱们在面临代码设计问题时更加成竹在胸。单刀直入咱们直奔主题,分类出现23种设计模式的庐山真面目: 创立型 (5)Creational结构型 (7)Structural行为型 (11)Behavioral工厂办法 Factory method形象工厂 Abstract factory建造者 Builder原型 Prototype单例 SingleTon适配器 Adapter桥接 Bridge组合 Composite装璜 Decorator外观 Facade享元 Flyweight代理 Proxy责任链 Chain of responsibility命令 Command解释器 Interpreter迭代器 Iterator中介 Mediator备忘录 Memento观察者 Observer状态 State策略 Strategy模板办法 Template method访问者 Visitor这23种设计模式源于GoF所著的"Design Patterns - Elements of Reusable Object-Oriented Software" 一书(也有将该书间接简称为GoF),译著为 “设计模式:可复用面向对象软件的根底”。原书将这23种设计模式分为三类: 创立型蕴含5种模式,波及对象/对象组合的创立构建。结构性蕴含7种模式,波及对象/类之间的关系。行为型蕴含11种模式,波及对象/类的行为、状态、流程。从该书的题目咱们能够理解到,设计模式是一个面向对象开发方法下的概念,是解决代码设计/软件架构问题的可复用的元素,同时是根本元素(elements)。援用原书的例子,咱们大家所熟识的MVC模式,Model-View-Controller,就能够解构为几种设计模式的组合演变,比方能够在View和Model的关系中看到观察者模式 Observer、组合模式 Composite、装璜模式 Decorator,在Controller中发现策略模式的影子。通过对23种根底模式的有机利用和联合,能够进一步演化出更简单的软件架构。限于篇幅,本文不会解说每种设计模式的定义和背景,读者能够参考设计模式简介来学习定义。 设计模式的UML、类比和范例这个局部,咱们逐渐从尝鲜到类比,深刻了解一些比拟常见乏味的设计模式的UML及其经典实例。GoF原书中也举荐学习者从“模式怎么互相关联”以及“钻研目标类似的模式“登程来学习和抉择设计模式。首先看看最简略常见的策略模式和另一个同属行为型模式的状态模式: 策略模式 Strategy状态模式 StateUML范例- Comparator#compare() 和 Collections#sort()- Spring Security: PasswordEncoder- 规范范例: javax.faces.lifecycle.LifeCycle#execute()- 形似样例:Java Thread State, ExoPlayer概述让内部对算法的互相替换无感容许一个对象依据外部状态扭转行为关键字Strategy, ruleState, switch, phase, lifecycle外围角色StrategyState策略模式和状态模式在UML图形上十分相像,他们之间的次要区别如下: 状态对象能够持有上下文对象(调用方),但策略模式个别存在这种依赖。状态模式能够在彼此之间进行跳转替换,比方调用了播放器的play办法,那么状态可能从stop->playing,这个操作能够用状态对象实现。一个策略和调用方的关系(依赖)可能弱于状态和上下文对象的关系(持有、属性)。策略的不同可能只影响一个行为,然而状态的不同影响状态持有对象行为的方方面面。整体上策略模式要比状态模式更加扼要易懂,利用场景更广,在大型项目中的利用也随处可见。而状态模式尽管也是对常见概念的形象,其利用却绝对无限,其起因可能是,在更多的状况下,把行为的差别定义在不同的状态中,可能并非合乎直觉的操作:与其把状态也定义为对象承载行为,不如把状态定义为一个标记,间接用if或switch判断来的间接。或者换言之,大多数状况下,问题还没有简单到要用状态模式的水平。 借助这种比照的视角,咱们来学习更多模式。先看看以下三种结构型设计模式: ...

January 16, 2023 · 2 min · jiezi

关于设计模式:吃透JS设计模式Design-pattern

大家好!我是 代码诗人_,明天咱们来谈谈js中的设计模式。 一、为什么会有设计模式这个概念如果你须要一种模式,那肯定是哪里出了问题。编程语言没有美中不足的,因为其的天生缺点,所以不得不去寻求和总结一种通用的解决方案,至此就衍生出了这种通用的解决办法——设计模式(Design pattern),故:设计模式 是解决软件开发某些特定问题而提出的一些解决方案也能够了解成解决问题的一些思路 二、设计模式的作用通过设计模式能够帮忙咱们加强代码的可重用性、可扩充性、 可维护性、灵活性好。咱们应用设计模式最终的目标是实现代码的 高内聚和低耦合。 那什么是高内聚和低耦合? 举例一个生存中的例子,例如一个公司,个别都是各个部门各司其职,互不干涉。各个部门须要沟通时通过专门的负责人进行对接。在软件外面也是一样的 一个功能模块只是关注一个性能,一个模块最好只实现一个性能。这个是所谓的内聚。 模块与模块之间、零碎与零碎之间的交互,是不可避免的, 然而咱们要尽量减少因为交互引起的单个模块无奈独立应用或者无奈移植的状况产生, 尽可能多的独自提供接口用于对外操作, 这个就是所谓的低耦合 三、设计模式的六大准则1、开闭准则(Open Close Principle)开闭准则的意思是:对扩大凋谢,对批改敞开。在程序须要进行拓展的时候,不能去批改原有的代码。为了使程序的扩展性好,易于保护和降级,咱们须要应用接口和抽象类,前面的具体设计中咱们会提到这点。 2、里氏代换准则(Liskov Substitution Principle)里氏代换准则是面向对象设计的根本准则之一是继承复用的基石是对开闭准则的补充。 (实现开闭准则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换准则是对实现抽象化的具体步骤的标准。)里氏代换准则中说,任何基类能够呈现的中央,子类肯定能够呈现。 3、依赖倒转准则(Dependence Inversion Principle)这个准则是开闭准则的根底,具体内容:针对接口编程,依赖于形象而不依赖于具体 4、接口隔离准则(Interface Segregation Principle)应用多个隔离的接口,比应用单个接口要好。升高类之间的耦合度 5、迪米特法令,又称起码晓得准则(Demeter Principle)起码晓得准则是指:一个实体该当尽量少地与其余实体之间产生相互作用,使得零碎功能模块绝对独立。 6、合成复用准则(Composite Reuse Principle)合成复用准则是指:尽量应用合成/聚合的形式,而不是应用继承。 三、设计模式的实现请点击 工厂模式单例模式 待续... 总结设计模式是在软件开发过程中面临的个别问题的解决方案。设计模式的应用是为了重用代码、让代码更容易被别人了解、保障代码可靠性。设计模式使代码编制真正工程化,设计模式是软件工程的基石,我的项目中正当地使用设计模式能够完满地解决很多问题。便于降级和保护的软件设计思维,它强调升高依赖,升高耦合( 高内聚和低耦合)

January 16, 2023 · 1 min · jiezi

关于设计模式:设计模式之单例模式

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址:https://github.com/Tyson0314/... 单例模式单例模式(Singleton),目标是为了保障在一个过程中,某个类有且仅有一个实例。 因为这个类只有一个实例,所以不能让调用方应用new Xxx()来创立实例。所以,单例的构造方法必须是private,这样就避免了调用方本人创立实例。 单例模式的实现须要三个必要的条件: 单例类的构造函数必须是公有的,这样能力将类的创立权管制在类的外部,从而使得类的内部不能创立类的实例。单例类通过一个公有的动态变量来存储其惟一实例。单例类通过提供一个公开的静态方法,使得内部使用者能够拜访类的惟一实例。另外,实现单例类时,还须要思考三个问题: 创立单例对象时,是否线程平安。单例对象的创立,是否延时加载。获取单例对象时,是否须要加锁。上面介绍几种实现单例模式的形式。 饿汉模式JVM在类的初始化阶段,会执行类的静态方法。在执行类的初始化期间,JVM会去获取Class对象的锁。这个锁能够同步多个线程对同一个类的初始化。 饿汉模式只在类加载的时候创立一次实例,没有多线程同步的问题。单例没有用到也会被创立,而且在类加载之后就被创立,内存就被节约了。 public class Singleton { private static Singleton instance = new Singleton(); private Singleton() {} public static Singleton newInstance() { return instance; } }饿汉式单例的长处: 单例对象的创立是线程平安的;获取单例对象时不须要加锁。饿汉式单例的毛病:单例对象的创立,不是延时加载。 懒汉式与饿汉式思维不同,懒汉式反对延时加载,将对象的创立提早到了获取对象的时候。不过为了线程平安,在获取对象的操作须要加锁,这就导致了低性能。 public class Singleton { private static final Singleton instance; private Singleton () {} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }}上述代码加的锁只有在第一次创建对象时有用,而之后每次获取对象,其实是不须要加锁的(双重查看锁定优化了这个问题)。 懒汉式单例长处: 对象的创立是线程平安的。反对延时加载。懒汉式单例毛病: ...

January 11, 2023 · 2 min · jiezi

关于设计模式:面试的时候别再说你不会设计模式了

前言最近在设计一个对某个中间件的测试计划,这个测试计划须要蕴含不同的测试逻辑,但雷同的是须要对各个环节进行记录;比方统计耗时、调用告诉 API 等雷同的逻辑。 如果每个测试都独自写这些逻辑那无疑是做了许多反复工作了。 基于以上的特色很容易能想到模板办法这个设计模式。 这是一种有下层定义框架,上层提供不同实现的设计模式。 比方装修房子的时候业主能够依照本人的爱好对不同的房间进行装修,然而整体的户型图不能做批改,比方承重墙是必定不能打的。 而这些固定好的条条框框就是下层框架给的束缚,上层不同的实现就有业主本人决定;所以对于整栋楼来说框架都是固定好的,让业主在无限的范畴内自由发挥也不便物业的治理。 具体实现以我这个案例的背景为例,首先须要定义出下层框架: JavaEvent 接口: public interface Event { /** * 新增一个工作 */ void addJob(); /** * 单个工作执行结束 * * @param jobName 工作名称 * @param finishCost 工作实现耗时 */ void finishOne(String jobName, String finishCost); /**单个工作执行异样 * @param jobDefine 工作 * @param e 异样 */ void oneException(AbstractJobDefine jobDefine, Exception e); /** * 所有工作执行结束 */ void finishAll();} public void start() { event.addJob(); try { CompletableFuture.runAsync(() -> { StopWatch watch = new StopWatch(); try { watch.start(jobName); // 不同的子业务实现 run(client); } catch (Exception e) { event.oneException(this, e); } finally { watch.stop(); event.finishOne(jobName, StrUtil.format("cost: {}s", watch.getTotalTimeSeconds())); } }, TestCase.EXECUTOR).get(timeout, TimeUnit.SECONDS); } catch (Exception e) { event.oneException(this, e); } } /** Run busy code * @param client * @throws Exception e */ public abstract void run(Client client) throws Exception; 其中最外围的就是 run 函数,它是一个形象函数,具体实现交由子类实现;这样不同的测试用例之间也互不烦扰,同时整体的流程完全相同: ...

December 27, 2022 · 2 min · jiezi

关于设计模式:百度工程师教你玩转设计模式装饰器模式

作者 | 北极星小组 想要写好代码,设计模式(Design Pattern)是必不可少的基本功,设计模式是对面向对象设计(Object Oriented Design)中重复呈现的一类问题的一种解决方案,本篇介绍装璜器模式(Decorator Pattern)。 在咱们日常的开发过程中,一个最常见的场景就是在已有的根底上新增性能,惯例的做法有以下几种: 批改已有的类:违反开闭准则。减少新的子类:每次都得新增大量对应的类,随着性能的减少,子类越来越收缩。在此场景下,装璜器模式就能够体现出它的劣势了,它容许在不批改原有对象的前提下,灵便的扩大已有类的性能。上面是装璜器模式的一个通用的类图: △UML 其中的各个类的作用如下: 形象组件(Component): 能够是接口或者抽象类,它定义了具体类以及装璜器所领有的办法。具体组件(ComponentA, ComponentB):具体的组件,实现或者继承自形象组件。能够了解成上述场景中已存在的类。形象装璜器(Decorator): 通常为抽象类,持有一个被装璜的对象,定义了具体装璜器的办法。此类非必须也能够没有,具体装璜器也可间接继承或者实现形象组件。具体装璜器(DecoratorX, DecoratorY): 具体的装璜器,继承自形象装璜器(也可间接继承自形象组件),扩大了形象组件的某些性能。上面,将通过3个具体的案例的解说装璜器的应用形式,不便大家进一步的了解。 一、装璜器在工作解决场景的利用在理论的开发中,咱们常常须要定义不同的类来解决各种不同的工作。假如一个这样的场景,咱们的零碎有多个具体的类,用来解决不同类型的工作。当初须要增加一个性能,就是在解决完工作后收回一条音讯。针对这个场景,应用装璜器模式的实现思路如下: 形象组件(TaskProcessor):解决工作的抽象类(亦可通过接口实现),定义一个通用的工作解决办法process()。具体组件(TaskProcessorA, TaskProcessorB): 负责实现具体的工作解决逻辑形象装璜器(TaskProcessDecorator):持有一个工作解决对象实例具体装璜器(AfterTaskProcessDecorator):实现具体的工作解决实现后的音讯告诉扩大能力具体的代码如下: package com.baidu.demo;public class Decorator { // 形象组件 static abstract class TaskProcessor { abstract void process(); } // 具体组件 static class TaskProcessorA extends TaskProcessor { @Override void process() { System.out.println("TaskProcessorA解决实现"); } } // 具体组件 static class TaskProcessorB extends TaskProcessor { @Override void process() { System.out.println("TaskProcessorB解决实现"); } } // 形象装璜器 static abstract class TaskProcessDecorator extends TaskProcessor { protected TaskProcessor processor; public TaskProcessDecorator(TaskProcessor processor) { this.processor = processor; } abstract void process(); } // 具体装璜器 static class AfterTaskProcessDecorator extends TaskProcessDecorator { public AfterTaskProcessDecorator(TaskProcessor processor) { super(processor); } @Override void process() { processor.process(); afterProcess(); } void afterProcess() { System.out.println("工作处理完毕,发送音讯..."); } } public static void main(String[] args) { // 扩大之前 System.out.println("==========before=========="); TaskProcessor processorA = new TaskProcessorA(); processorA.process(); TaskProcessor processorB = new TaskProcessorB(); processorB.process(); // 装璜器扩大之后:TaskProcessorA TaskProcessorB并未做任何批改,即可实现性能的扩大 System.out.println("==========after=========="); TaskProcessor decoratorA = new AfterTaskProcessDecorator(processorA); decoratorA.process(); TaskProcessor decoratorB = new AfterTaskProcessDecorator(processorB); decoratorB.process(); }}// 输入后果如下==========before==========TaskProcessorA解决实现TaskProcessorB解决实现==========after==========TaskProcessorA解决实现工作处理完毕,发送音讯...TaskProcessorB解决实现工作处理完毕,发送音讯...二、装璜器在文件IO场景的利用装璜器模式,一个典型的利用就是文件IO操作,最根底的类实现字节流读取类,应用装璜器模式能够封装文件字节流读取类,而后能够持续封装可缓存的文件字节流读取类,在我的项目中按需应用。具体实现如下: ...

December 23, 2022 · 3 min · jiezi

关于设计模式:824页23种设计模式全解析搞定设计模式各种难题

什么是设计模式设计模式(英语 design pattern)是对面向对象设计中重复呈现的问题的解决方案。这个术语是在1990年代由Erich Gamma等人从建筑设计畛域引入到计算机科学中来的。这个术语的含意还存有争议。算法不是设计模式,因为算法致力于解决问题而非设计问题。设计模式通常形容了一组互相严密作用的类与对象。设计模式提供一种探讨软件设计的公共语言,使得纯熟设计者的设计教训能够被初学者和其余设计者把握。设计模式还为软件重构提供了指标。 随着软件开发社群对设计模式的趣味日益增长,曾经出版了一些相干的专著,定期召开相应的研讨会,而且Ward Cunningham为此创造了WikiWiki用来交换设计模式的教训。 总之,设计模式就是为了解决某类反复呈现的问题而呈现的一套胜利或无效的解决方案 设计模式的分类总体来说设计模式分为三大类: 创立型模式,共五种:工厂办法模式、形象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装璜器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一种:策略模式、模板办法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 为了帮忙大家更好的学习设计模式,小编淘到一本《设计模式之禅》,这本书一度屠榜GitHub、知乎;本书分为五大部分,废话不多说,给大家展现一下目录 目录 具体内容因为篇幅的起因,以下只展现局部重要内容,须要完整版文档的小伙伴,【间接点击此处】即可收费获取!! 第一局部第1章 繁多职责准则第2章 里氏替换准则第3章 依赖倒置准则第4章 接口隔离准则第5章 迪米特法令第6章 开闭准则 第二局部第7章 单例模式第8章 工厂办法模式第9章 形象工厂模式第10章 模板办法模式第11章 建造者模式第12章 代理模式第13章 原型模式第14章 中介者模式第15章 命令模式第16章 责任链模式第17章 装璜模式第18章 策略模式第19章 适配器模式第20章 迭代器模式第21章 组合模式第22章 观察者模式第23章 门面模式第24章 备忘录模式第25章 访问者模式第26章 状态模式第27章 解释器模式第28章 享元模式第29章 桥梁模式 第三局部第30章 创立类模式大PK第31章 构造类模式大PK第32章 行为类模式大PK第33章 跨战区PK 第四局部第34章 命令模式+责任链模式第35章 工厂办法模式+策略模式第36章 观察者模式+中介者模式 第五局部第37章 MVC框架第38章 新模式 ...

November 27, 2022 · 1 min · jiezi

关于设计模式:工作中常用的设计模式责任链模式

个别做业务开发,不太容易有大量应用设计模式的场景。这里总结一下在业务开发中应用较为频繁的设计模式。当然语言为Java,基于Spring框架。1 责任链模式(Chain of Responsibility Pattern)对数据流、对象做一系列过滤、校验、解决等操作,该操作通常是有序的。该场景在生活中还是很常见的,如大家常常举例的各种审批流。再如面试,须要通过一面、二面、三面、HR面等,最终拿下Offer。这些都属于责任链的场景, 责任链模式个别有3个角色: Client: 客户端。用来编排处理器,可动态、也可运行时动静生成。相似单链表。Handler: 接口或抽象类。约定处理函数名称、参数等。ConcreteHandler: 具体处理器。这种呈现的场景其实挺多,但真正应用的却不是很多。这就要提到责任链的几个毛病:灵便动静既是长处也是毛病,使得程序不够直观,流程不够明了。甚至可能呈现循环援用(死循环)的状况。 责任链的编排个别有两种: 内部编排:具体处理器,仅依据Contex参数进行解决,并将后果回写Contex。外部不做编排。绝对比拟独立(纯正)的逻辑处理单元。外部编排:相似单链表。在执行过程中,依据Context参数的处理结果,判断是否须要进行下一步(进入下一个处理器)。绝对内部编排,灵便度略低一些。1.1 理论业务场景在用户留资进线场景中,咱们须要依据线索的渠道号、落地页起源、学科等做不同的逻辑解决。但在未失去理论参数前,咱们是不能确定具体要走哪些处理器。一些业务规定(简化): 渠道号(channel)不能为空某些非凡渠道号,推荐人不能为空某些落地页起源(lpv),偏好语言不能为空只有全副符合条件的线索,能力理论进入到CRM零碎中。 线索 LeadsBO@Data@Builderpublic class LeadsBO { // 渠道号 private String channel; // 推荐人ID private Long referrerId; // 学科 1:中文 2:英文 private Integer subject; // 落地页版本(Landing Page Version) private String lpv; // 偏好语言 private String preferenceLanguage; // 责任链回写 // 数据是否无效 @Builder.Default private boolean valid = true; // 异样信息(谬误日志) private String errMsg;}线索过滤器(即Handler处理器) Filter/** * 线索过滤器 */public interface Filter { void process(LeadsBO bo);}4个具体处理器/** * 渠道号过滤器 */@Component("channel")public class ChannelFilter implements Filter { @Override public void process(LeadsBO bo) { if (StringUtils.isBlank(bo.getChannel())) { bo.setValid(false); bo.setErrMsg("channel为空"); } }}/** * 推荐人过滤 */@Component("referrer")public class ReferrerFilter implements Filter { private static final Set<String> CHANNELS = Set.of( "LP-XX-XX-01", "LP-XX-XX-02" ); @Override public void process(LeadsBO bo) { final String channel = bo.getChannel(); final Long referrerId = bo.getReferrerId(); if (CHANNELS.contains(channel) && Objects.isNull(referrerId)) { bo.setValid(false); bo.setErrMsg("特定渠道号, 推荐人不能为空"); } }}/** * 落地页版本号校验 */@Component("lpv")public class LpvFilter implements Filter { @Override public void process(LeadsBO bo) { final String lpv = bo.getLpv(); if (StringUtils.isNoneBlank(lpv) && lpv.startsWith("XZ") && StringUtils.isBlank(bo.getPreferenceLanguage())) { bo.setValid(false); bo.setErrMsg("偏好语言不能为空"); } }}/** * 学科过滤器 * */@Component("subject")public class SubjectFilter implements Filter { @Override public void process(LeadsBO bo) { final Integer subject = bo.getSubject(); if (Objects.isNull(subject) || (subject != 1 && subject != 2)) { bo.setSubject(1); } }}能够看到,咱们在定义处理器时,并没有在处理器外部动静指定下一个解决。咱们将处理器的编排放在内部设置,这样更加的灵便一下。借助于Spring,给具体解决增加别名,不便后续应用。 ...

November 25, 2022 · 2 min · jiezi

关于设计模式:设计模式在前端开发中的粗浅应用

收场不晓得怎么收场,就只能伪装本人很懂的先来介绍两个概念。 设计模式官网的解释:设计模式代表了最佳实际。作为一个前端白菜,浅显的了解一下:设计模式其实就是代码结构设计中的最佳解决方案。 大佬们,再看:有这么一种设计模式 —— 建造者模式(Builder Pattern): 应用多个简略的对象一步一步构建成一个简单的对象。 组件化组件化是指解耦简单零碎时将多个功能模块拆分、重组的过程。目标为理解耦:把简单零碎拆分成多个组件,拆散组件边界和责任,便于独立降级和保护。持续浅显的了解一下,就是将简单的性能拆解成繁多性能的小整机。 那是不是能够这么了解:前端的组件化开发其实就是建造者模式的实际。 实际假设一种场景须要一个用户注册的性能。要求以邮箱为用户名;须要明码,并确认明码;有昵称,然而可选填;一个提交按钮。 剖析很显然,这里比拟显著的整机有两种:带题目的输入框 和 带文字的按钮。所以,咱们须要做两个整机? 答案是:不须要!在理论状况下,按钮必定是一个须要被解决的组件。然而,就以后场景而言,输入框才是咱们要去拆解的组件。也就是说,拆解的最终目标是为了复用。 So, no more BB~ 代码走起。 编写代码以vue为例根底组件:components/BaseInput.vue <template> <div> <label>{{labelText}}</label> <input :type="inputType" :placeholder="inputPlaceholder" /> </div></template><script> export default { props: { labelText: String, inputType: String, inputPlaceholder: String } }</script><style></style>页面援用:pages/register.vue <template> <BaseInput label-text="用户名" input-type="text"></BaseInput> <BaseInput label-text="明码" input-type="password"></BaseInput> <BaseInput label-text="确认明码" input-type="password"></BaseInput> <BaseInput label-text="昵称" input-type="text"></BaseInput> <button>提交</button></template><script> import BaseInput from '../components/BaseInput.vue' export default { components: { BaseInput } }</script><style></style>至此,曾经实现了注册的根本组件结构。 总结简略的宰割组件很容易,不过更重要的是要思而后动。设计模式说白了就是优良的程序员们对编程思维优良见解的总结。当遇到理论问题时应用设计模式的思维形式或者能关上新世界的大门。

November 24, 2022 · 1 min · jiezi

关于设计模式:工作中常用的设计模式适配器模式

个别做业务开发,不太容易有大量应用设计模式的场景。这里总结一下在业务开发中应用较为频繁的设计模式。当然语言为Java,基于Spring框架。1 适配器模式(Adapter Pattern)已存在的接口、服务,跟咱们所需、目标接口不兼容时,咱们须要通过肯定的办法将二者进行兼容适配。一个常见的例子,家用电源(国标)220V,而手机规范输出个别为5V,此时咱们便须要一个适配器来将220V转换为5V应用。 适配器模式个别有3个角色: Target: 指标接口Adaptee: 须要进行适配的类(受革新者)Adapter: 适配器(将Adaptee转为Target)这个呈现的场景其实挺多,但理论齐全依照适配器模式编写代码的场景可能并不多。简略业务场景,间接就将适配、兼容代码混淆在业务代码中了。并没有将其摘出来解决。大部分业务代码,可能后续并不会再做扩大之类,适度设计反而会升高可读性并减少代码的复杂性。 适配器模式个别分为类适配器和对象适配器。类适配器的话,应用继承形式实现:class Adapter extends Adaptee implements Target;而对象适配器的话,则应用组合形式实现。这种状况更灵便一些。毕竟大家都举荐多用组合少用继承。 在学生产生约课完课等事件时,咱们须要将局部数据同步到内部CRM零碎中。课程的话,按班级类型分为:1v1,小班课、大班课。不同的班级类型课程数据有所不同。事件上报时,并不是全量数据,有些数据须要消费者按需查问。如课程课程编号、名称、预约上课工夫等。 不同班级类型的课程由三个不同的FeignClient(Adaptee)提供服务,而咱们想要的就是查问课程相干信息(Target)。 为了模仿服务提供者,咱们Mock如下服务。 @Data@Builderpublic class OneClass { // 课程编号 private String lessonNo; // 课程名称 private String lessonName; // 其余信息 private String one;}@Data@Builderpublic class SmallClass { // 课程编号 private String lessonNo; // 课程名称 private String lessonName; // 其余信息 private String small;}@Data@Builderpublic class BigClass { // 课程编号 private String lessonNo; // 课程名称 private String lessonName; // 其余信息 private String big;}public interface RemoteClassClient { default OneClass getOne() { return OneClass.builder().lessonNo("one").lessonName("1V1").build(); } default SmallClass getSmall() { return SmallClass.builder().lessonNo("small").lessonName("小班课").build(); } default BigClass getBig() { return BigClass.builder().lessonNo("big").lessonName("大班课").build(); }}public class RemoteClassClientImpl implements RemoteClassClient {}该服务对立由RemoteClassClient对外提供各个班级类型的查问服务。 ...

November 24, 2022 · 3 min · jiezi

关于设计模式:工作中常用的设计模式策略模式

个别做业务开发,不太容易有大量应用设计模式的场景。这里总结一下在业务开发中应用较为频繁的设计模式。当然语言为Java,基于Spring框架。1 策略模式(Strategy Pattern)一个类的行为或办法,在运行时能够依据条件的不同,有不同的策略(行为、办法)去执行。举个简略的例子:去下班,能够骑共享单车、能够抉择公交车、也能够乘坐地铁。这里的乘坐什么交通工具就是针对去下班这个行为的策略(解决方案)。 策略模式个别有3个角色: Context: 策略的上下文执行环境Strategy: 策略的形象ConcreteStrategy: 策略的具体实现这个呈现的场景其实还很多。如之前做商城时遇到的登录(手机号、微信、QQ等),及优惠券(满减券、代金券、折扣券等)。这里次要讲一下最近遇到的两种。一种是事后晓得要走哪个策略,一种是须要动静计算能力确定走哪种策略。 1.1 动态(参数)策略在做增长零碎时,用户留资进线须要依据不同起源走不同的解决逻辑。而这种起源,在数据呈现时就能确定。 SyncContext/** * 同步上下文 * */@Data@Builderpublic class SyncContext { // 工作ID private Long taskId; // 工作类型 1: 天然注册; 2: 团购用户; 3: 落地页留资 private Integer taskType; // 所有留资相干信息(疏忽细节) private Object reqVO; // 存储执行策略名称(假装执行后果) private String respVO;}SyncStrategy/** * 同步策略 * */public interface SyncStrategy { /** * 具体策略 * @param ctx Context */ void process(SyncContext ctx);}OtSyncStrategy/** * 天然注册 * */@Slf4j@Servicepublic class OtSyncStrategy implements SyncStrategy, BeanNameAware { private String beanName; @Override public void process(SyncContext ctx) { log.info("[天然注册] {}", ctx); ctx.setRespVO(beanName); } @Override public void setBeanName(String s) { beanName = s; }}AbSyncStrategy/** * 团购用户 * */@Slf4j@Servicepublic class AbSyncStrategy implements SyncStrategy, BeanNameAware { private String beanName; @Override public void process(SyncContext ctx) { log.info("[团购用户] {}", ctx); ctx.setRespVO(beanName); } @Override public void setBeanName(String s) { beanName = s; }}DefaultSyncStrategy/** * 落地页注册(Default) * */@Slf4j@Servicepublic class DefaultSyncStrategy implements SyncStrategy, BeanNameAware { private String beanName; @Override public void process(SyncContext ctx) { log.info("[落地页注册] {}", ctx); ctx.setRespVO(beanName); } @Override public void setBeanName(String s) { beanName = s; }}至此,策略模式的三个角色已凑齐。但仿佛还有一些问题,SyncContext中有taskType,然而该怎么与具体的策略匹配呢?咱们能够借助Spring框架的依赖注入管理策略。 ...

November 23, 2022 · 4 min · jiezi

关于设计模式:常见结构型设计模式在Go中的应用

上一篇创立型(单例/工厂/建造者)设计模式在Go中的利用介绍了一些常见的创立型设计模式,创立型次要解决了类的创立问题,使代码更易用,而咱们常常遇到另外一种问题:类或对象如何组合在一起效率更高,结构型模式便是解决这类问题的经典构造。 结构型模式包含:代理模式、桥接模式、装璜器模式、适配器模式、门面模式、组合模式、享元模式。 接下来咱们就来看一看它们的利用场景: 一、代理模式原理代理模式是指在不扭转原始类 (或叫被代理类)代码的状况下,通过引入代理类来给原始类附加性能。 代理管制着对于原对象的拜访,并容许在将申请提交给对象前后进行一些解决。 个别状况下,咱们让代理类和原始类实现同样的接口,因而你可将其传递给任何一个应用理论服务对象的客户端。 利用场景代理模式罕用在业务零碎中开发一些非功能性需要,比方:监控、统计、鉴权、限流、事务、幂等、日志。咱们将这些附加性能与业务性能解耦,放到代理类对立解决,让程序员只须要关注业务方面的开发。除此之外,代理模式还能够用在 RPC、缓存等利用场景中。 利用server提供拜访服务,代理在它的根底上减少了接口限流的性能 package mainimport "fmt"type server interface { handleRequest(string, string) (int, string)}type Application struct {}func (a *Application) handleRequest(url, method string) (int, string) { if url == "/app/status" && method == "GET" { return 200, "Ok" } if url == "/create/user" && method == "POST" { return 201, "User Created" } return 404, "Not Ok"}type ApplicationProxy struct { application *Application maxAllowedRequest int rateLimiter map[string]int}func newApplicationProxy() *ApplicationProxy { return &ApplicationProxy{ application: &Application{}, maxAllowedRequest: 2, rateLimiter: make(map[string]int), }}func (p *ApplicationProxy) handleRequest(url, method string) (int, string) { allowed := p.checkRateLimiting(url) if !allowed { return 403, "Not Allowed" } return p.application.handleRequest(url, method)}func (p *ApplicationProxy) checkRateLimiting(url string) bool { if p.rateLimiter[url] == 0 { p.rateLimiter[url] = 1 } if p.rateLimiter[url] > p.maxAllowedRequest { return false } p.rateLimiter[url] = p.rateLimiter[url] + 1 return true}func main() { server := newApplicationProxy() appStatusURL := "/app/status" createuserURL := "/create/user" httpCode, body := server.handleRequest(appStatusURL, "GET") fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body) httpCode, body = server.handleRequest(appStatusURL, "GET") fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body) httpCode, body = server.handleRequest(appStatusURL, "GET") fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body) httpCode, body = server.handleRequest(createuserURL, "POST") fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body) httpCode, body = server.handleRequest(createuserURL, "GET") fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)}打印后果: ...

November 6, 2022 · 4 min · jiezi

关于设计模式:Go应用设计模式之创建型

创立型模式提供了创建对象的机制,可能晋升已有代码的灵活性和可复用性。上面别离来说一下常见的几种创立性设计模式:一、单例模式定义:一个类只容许创立一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例模式。 应用场景:从业务概念上,有些数据在零碎中只应该保留一份,就比拟适宜设计为单例类。比方,零碎的配置信息类。除此之外,咱们还能够应用单例解决资源拜访抵触的问题。 实现概括起来,要实现一个单例,咱们须要关注的点无外乎上面几个: 构造函数须要是 private 拜访权限的,这样能力防止内部通过 new 创立实例;思考对象创立时的线程平安问题;思考是否反对提早加载;思考 getInstance() 性能是否高(是否加锁)。依据是否反对提早加载,单例模式分为饿汉式和懒汉式1. 饿汉式在类加载的时候,instance 动态实例就曾经创立并初始化好 了,所以,instance 实例的创立过程是线程平安的。 package singletontype Singleton struct{}var singleton *Singletonfunc init() { singleton = &Singleton{}}// GetInstance 获取实例func GetInstance() *Singleton { return singleton}2. 懒汉式(双重检测)懒汉式绝对于饿汉式的劣势是反对提早加载,然而因为须要加锁,有性能问题。 双重检测:在懒汉式的实现形式中,只有 instance 被创立之后,即使再调用 getInstance() 函数也不会再进入到加锁逻辑中,这样便既反对提早加载、又反对高并发了。package singletonimport "sync"var ( lazySingleton *Singleton once = &sync.Once{})// GetLazyInstance 懒汉式func GetLazyInstance() *Singleton { if lazySingleton == nil { once.Do(func() { lazySingleton = &Singleton{} }) } return lazySingleton}饿汉式将耗时的初始化操作,提前到程序启动的时候实现,这样就能防止在程序运行的时候,再去初始化导致的性能问题。 如果实例占用资源多,依照 fail-fast 的设计准则(有问题及早裸露),那咱们也心愿在程序启动时就将这个实例初始化好。如果资源不够,咱们能够立刻去修复。 综合来说,饿汉式还是比反对双重检测的懒汉式更举荐应用。 ...

November 3, 2022 · 3 min · jiezi

关于设计模式:设计模式之禅01单一职责原则

繁多职责准则1.1 我是“牛”类,我能够负责多职吗繁多职责准则,英文名称是Single Responsibility Principle,简称是SRP,定义是应该有且仅有一个起因引起类的变更。 什么是类的职责,以及怎么划分类的职责? 举例:rbac模型 这个接口设计的存在问题:用户属性和用户行为没有离开 把用户信息抽取成一个BO(Business Object,业务对象),把行为抽取成一个Biz(Business Logic,业务逻辑),咱们面向接口编程,所以产生的UserInfo对象能够当成IUserBO接口应用,也能够录成IUserBiz接口应用 IUserInfo userInfo = new UserInfo();IUserBO userBO = (IUserBO)userInfo;userBO.setPassword("abc");IUserBiz userBiz = (IUserBiz)userInfo;userBiz.deleteUser();在理论应用中,咱们更偏向于应用两个不同的类或接口,如下: 1.2 绝杀技,突破你的传统思维举例:电话设计 这么设计的问题是IPhone接口不只有一个职责,别离为:一个是协定治理,一个是数据传送。 这样设计引起类间耦合过重、类的数量减少,人为地减少了设计的复杂性 这样设计,一个类实现两个接口,把两个职责交融在一个类中。 繁多职责准则的益处实现什么职责都有清晰明确的定义,这样类的复杂性升高,可读性进步,可维护性进步 1.3 我单纯,所以我高兴繁多职责实用于接口、类,同时也实用于办法。 要批改用户名称,就调用changeUserName办法;要批改家庭地址,就调用changeHomeAddress办法;要批改单位电话,就调用changeOfficeTel办法。每个办法的职责十分清晰明确,不仅开发简略,而且日后的保护也非常容易。 1.4 最佳实际大部分状况下类设计都是与繁多职责相违反的,类的繁多职责受到十分多因素的制约,事实你必须去思考我的项目工期、老本、人员技术水平、硬件状况、网络状况甚至有时候还要思考政府政策、垄断协定等因素。 对于繁多职责准则,倡议是接口肯定要做到繁多职责,类的设计尽量做到只有一个起因引起变动。 参考:《设计模式之禅》第2版

October 29, 2022 · 1 min · jiezi

关于设计模式:百度工程师教你玩转设计模式适配器模式

作者 | 北极星小组 在现实生活中,常常会遇到两个“对象” 因为接口不兼容而不能一起工作的场景,这时须要第三者进行适配,如:国内的充电线插头不肯定实用国外的插座须要借助转接头、SD卡无奈间接链接电脑须要借助读卡器、用直流电的笔记本电脑接交流电源时须要一个电源适配器等。 在软件设计中,须要开发的具备某种业务性能的组件在现有的组件库中曾经存在,但它们与以后零碎的接口标准不兼容,如果从新开发这些组件老本又很高,这时用适配器模式能很好地解决这些问题。 适配器模式(Adapter Pattern):是指将某个类的接口转化成客户端冀望的另一个接口,次要目标是兼容性,让本来因接口不匹配不能工作的两个类能够协同工作。 △适配器示意图 适配器模式蕴含如下角色: Target:指标抽象类, 定义客户要应用的接口Adapter:适配器类,将Adaptee的接口进行适配转换Adaptee:适配者类,须要被转换接口的对象Client:客户类,通过适配器接口Target去应用Adaptee的性能 △对象适配器 △类适配器 一、适配器模式在文档业务场景中的利用(对象适配器)微软office文档有两种数据格式,即office2007(OOXML格局)和Office2003(二进制格局)。在新业务场景中,因现有零碎曾经具备Office2007文档解决性能组件(数据、阅读器等),当初须要在此基础上裁减反对office2003格局的文档。即复用现有的office2007组件类,但接口与复用环境要求不统一,此时能够应用适配器模式。 示例应用对象适配器形式,疏忽业务解决细节,仅做流程上的形象来表明适配器模式的应用,依据模式构造形象出各个角色类: Doc2003指标抽象类Doc2007适配者类DocAdapter适配器类Document客户类// Document客户类应用方public class Document { public void View(Doc2003 doc) { doc.show() }}// Doc2003接口形象public interface IDoc2003 { void show();}// Doc2007适配者类public class Doc2007 { public void show() { System.out.println("office2007规范解决流程"); }}// DocAdapter适配器类public class DocAdapter implements IDoc2003 { private Doc2007 doc2007; public DocAdapter(Doc2007 doc2007){ this.doc2007 = doc2007; } @Override public void show() { System.out.println("适配器:这里省略了适配到2007的一堆适配逻辑..."); doc2007.show(); }}// 测试类public class Test { public static void main(String[] args) { Document document = new Document(); Doc2003 doc2003 = new DocAdapter(new Doc2007()) ; document.view(doc2003); }}二、适配器模式在替换依赖组件场景中的利用(类适配器)在理论的研发过程中,咱们常常会须要对依赖组件进行更新迭代。在替换时,相干调用代码,往往散布在十分多的中央,并且因为调用办法与参数不统一,一一批改工作量大,且存在脱漏危险,这时候能够应用类适配器,将接口对立,缩小相干代码的改变。 ...

October 26, 2022 · 2 min · jiezi

关于设计模式:JavaScript-设计模式-发布订阅模式

如果感觉文章不错,欢送关注、点赞和分享! 继续分享技术博文,关注微信公众号  前端LeBron 什么是公布 — 订阅模式公布 — 订阅模式,它定义程序对象之间一种一对多的依赖关系,当一个对象的状态产生扭转时,所有依赖它的对象都将失去告诉并执行相应操作。在日常生活中,常见的公布订阅模式有:订阅号,用户关注订阅号,内容创作者在平台公布内容后,平台遍历粉丝列表进行内容推送;销售中介,客户给销售人员留下了客户信息及联系方式,在新产品推出时,挨个给客户打电话进行采购,等等... 而公布订阅模式,个别由三类对象组成: 发布者 Publisher 事件发布者,将须要公布的事件传递给信道中介信道中介 Event Channel 作为公布订阅的中介,须要缓存相应事件的订阅者列表,在发布者公布时遍历订阅者列表并告诉它们订阅者 Subscriber 订阅事件,并定义事件公布后的操作,向信道中介发动订阅公布 — 订阅模式的利用在下面也介绍到了公布订阅模式在日常生活中以及前端开发工作中的应用场景,例如原生 DOM 事件,裸露了订阅接口后,开发者不须要重复查问该事件是否实现;异步编程的申请中,开发者无需轮询 HTTP 申请的状态,能够通过订阅申请的 success、error、update 等事件。在编程格调上,公布订阅模式让两个对象在松耦合的状况下建立联系,不再须要显式的将接口调用硬编码耦合进另一个对象,发布者和订阅者产生各自代码的变更都不会影响到对方,上面来看看前端开发最常见的公布订阅模式利用: DOM 事件和自定义事件。 DOM 事件由简入繁, DOM 事件是前端开发中最常见、简略的公布订阅模式利用document.body.addEventListener('click', function(){  alert(1);}, false );// 减少订阅者前者也不受影响document.body.addEventListener('click', function(){  alert(2);}, false );document.body.click(); // 模仿用户点击自定义事件由上述订阅号为例子实现一个繁难的自定义事件,进阶公布订阅模式利用const subscription = {};// 订阅者列表subscription.subscriber = [];// 订阅函数subscription.subscribe = function (fn) {  this.subscriber.push(fn);};// 公布函数subscription.publish = function () {  this.subscriber.forEach((fn) => {    fn.apply(this, arguments); });};// 粉丝 1 订阅subscription.subscribe((article) => {  console.log(`fans1 receive ${article}`);});// 粉丝 2 订阅subscription.subscribe((article) => {  console.log(`fans2 receive ${article}`);});// 订阅号公布const article = 'article'subscription.publish(article);// fans1 receive article// fans2 receive article通用公布 - 订阅模式下面自定义事件的例子,仅能局限在单个订阅号场景 ...

October 11, 2022 · 2 min · jiezi

关于设计模式:深入设计模式读书笔记一基础之类与对象实体

一、介绍面向对象程序设计(Object-Oriented Programming, 缩写为 OOP) 是一种范式。类:由变量和行为组成。对象:又名实体。成员变量和办法能够统称为类的成员。 二、类这是一个 UML 类图。 变量:这个cat类,来示意一只猫,猫都有许多根本属性: 名字 name、 性别 sex、 年龄 age、 体重 weight、 毛色 color 和最爱的食物等。 这些都是该类的成员变量。行为: 所有猫都有类似的行为: 它们会呼吸 breathe 、 进食 eat、奔跑 run、睡觉 sleep和喵喵叫 meow。这 些都是该类的办法。三、对象(实体)你敌人的猫“露露”也是 猫 这个类的一个实例。它领有与 “卡卡” 雷同的一组属性。不同之处在于这些属性的值: 她 的性别是“女孩”; 她的毛色不同; 体重较轻。 因而类就像是定义对象构造的蓝图,而对象则是类的具体实例。

October 10, 2022 · 1 min · jiezi

关于设计模式:面试题设计模式

什么是设计模式设计模式,是一套被重复应用、少数人通晓的、通过分类编目标、代码设计教训的总结。应用设计模式是为了可重用代码、让代码更容易被别人了解、保障代码可靠性、程序的重用性。 为什么要学习设计模式设计模式的实质是面向对象设计准则的理论使用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充沛了解 能够进步程序员的思维能力、编程能力和设计能力。使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。设计模式分类大体能够分为三种,每种加起又能够细分为23种。 创立型模式,共五种:工厂办法模式、形象工厂模式、单例模式、建造者模式、原型模式。结构型模式,共七种:适配器模式、装璜器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。行为型模式,共十一种:策略模式、模板办法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。设计模式的六大准则凋谢关闭准则准则思维:尽量通过扩大软件实体来解决需要变动,而不是通过批改已有的代码来实现变动形容:一个软件产品在生命周期内,都会发生变化,既然变动是一个既定的事实,咱们就应该在设计的时候尽量适应这些变动,以进步我的项目的稳定性和灵活性。长处:繁多准则通知咱们,每个类都有本人负责的职责,里氏替换准则不能毁坏继承关系的体系。里氏代换准则准则思维:应用的基类能够在任何中央应用继承的子类,完满的替换基类。大略意思是:子类能够扩大父类的性能,但不能扭转父类原有的性能。子类能够实现父类的形象办法,但不能笼罩父类的非形象办法,子类中能够减少本人特有的办法。长处:减少程序的健壮性,即便减少了子类,原有的子类还能够持续运行,互不影响。依赖倒转准则依赖倒置准则的核心思想是面向接口编程.依赖倒转准则要求咱们在程序代码中传递参数时或在关联关系中,尽量援用档次高的形象层类,这个是凋谢关闭准则的根底,具体内容是:对接口编程,依赖于形象而不依赖于具体。接口隔离准则这个准则的意思是:应用多个隔离的接口,比应用单个接口要好。还是一个升高类之间的耦合度的意思,从这儿咱们看出,其实设计模式就是一个软件的设计思维,从大型软件架构登程,为了降级和保护不便。所以上文中屡次呈现:升高依赖,升高耦合。例如:领取类的接口和订单类的接口,须要把这俩个类别的接口变成俩个隔离的接口迪米特法令(起码晓得准则)准则思维:一个对象该当对其余对象有尽可能少地理解,简称类间解耦大略意思就是一个类尽量减少本人对其余对象的依赖,准则是低耦合,高内聚,只有使各个模块之间的耦合尽量的低,能力进步代码的复用率。长处:低耦合,高内聚。繁多职责准则准则思维:一个办法只负责一件事件。形容:繁多职责准则很简略,一个办法 一个类只负责一个职责,各个职责的程序改变,不影响其它程序。 这是常识,简直所有程序员都会遵循这个准则。长处:升高类和类的耦合,进步可读性,减少可维护性和可拓展性,升高可变性的危险。单例模式什么是单例保障一个类只有一个实例,并且提供一个拜访该全局拜访点 那些中央用到了单例模式网站的计数器,个别也是采纳单例模式实现的,否则难以同步应用程序的日志利用,个别也都是单例模式实现,只有一个实例去操作才好,否则内容不好最佳显示。多线程的线程池的设计个别也是采纳单例模式,因为线程池要不便对池中的线程进行管制。Windows的工作管理器就是厂房典型的单例模式,他不能关上两个Windows的回收站也是经典的单例利用。在整个零碎运行过程中,回收站只能保护一个实例。单例模式的优缺点长处在单例模式中,流动的单例只有一个实例,对单例类的所有实例化失去的都是雷同的一个实例。这样就避免其余对象对本人的实例化,确保所有的对象都拜访一个实例。单例模式具备肯定的伸缩性,类本人来管制实例化过程,类就在扭转实例化过程上有相应的伸缩性。提供了对惟一实例的受控拜访。因为在零碎内存中只存在一个对象,因而能够节约系统资源,当须要频繁创立和销毁的对象时单例模式无疑能够提供零碎的性能。容许可变数目标实例。防止对共享资源的多重占用。毛病不适用于变动的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的谬误,不能保留彼此的状态。因为单例模式中没有形象层,因而单例的扩大有很大的艰难。单例类的职责过重,在肯定程序上违反了“繁多职责准则”。滥用单例将带来一些负面问题,如为了节俭资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而呈现连接池溢出;如果实例化的对象长时间不被利用,零碎会认为是垃圾而被回收,这将导致对象状态的失落。单例模式应用注意事项应用时不能用反射模式创立单例,否则会实例一个新的对象。应用懒单例模式时留神线程平安问题。饿单例模式和懒单例模式构造方法都是公有的,因而是不能被继承的,有些单例模式能够被继承(如注销式模式)单例避免反射破绽攻打private static boolean flag = false;private Singleton() { if (flag == flase) { flag = !flag; } eLse { thrown new RuntimeException("单例模式被进犯!"); }}如何抉择单例创立形式如果不须要提早加载单例,能够应用枚举或者饿汉式,相对来说枚举性好于饿汉式。如果须要提早加载,能够应用动态外部类或者懒汉式,相对来说动态外部类好于懒汉式。 单例创立形式饿汉式:类初始化时,会立刻加载该对象,线程天生平安,调用效率高。懒汉式:类初始化时,不会初始化该对象,真正须要应用的时候才会创立该对象,具备懒加载性能。动态外部形式:联合了懒汉式和饿汉式格子的长处,真正须要对象的时候才会加载,加载相似线程平安的。枚举单例:应用枚举实现单例模式 长处:实现简略、调用效率高,枚举自身就是单例,因为JVM从根本上提供保障!防止通过反射和反序列化的破绽毛病:没有提早加载双重检测锁形式:因为JVM实质重排序的起因,可能会初始化屡次,不举荐应用饿汉式类初始化时,会立刻加载该对象,线程天生平安,调用效率高。 public class Demo1 { private static Demo1 demo1 = new Demo1(); private Demo1() { System.out.println("公有Demo1结构参数初始化"); } public static Demo1 getInstance() { return demo1; } public static void main(String[] args) { Demo1 s1 = Demo1.getInstance(); Demo1 s2 = Demo1.getInstance(); System.out.println(s1 == s2); }}懒汉式类初始化时,不会初始化该对象,真正须要应用的时候才会创立该对象,具备懒加载性能。 ...

September 26, 2022 · 6 min · jiezi

关于设计模式:为什么要学习GoF设计模式

学习 GoF 设计模式以解决软件设计中的问题 “不思考变动的设计可能会在将来面临重大的从新设计危险。” :埃里希伽玛 在面向对象设计中,模式是常见问题的一种典型解决方案。当一个解决方案在各种我的项目中一次又一次地呈现时,最终会有人为其命名并详细描述它。这就是发现模式的形式。模式就像预制的蓝图,咱们能够对其进行自定义以解决代码中重复呈现的问题。模式不是一段特定的代码,而是解决特定问题的个别思路或者概念。咱们能够遵循模式详细信息,并施行适宜程序的解决方案。1995 年,Erich Gamma、John Vlissides、Ralph Johnson 和 Richard Helm 出版了《Design Patterns: Elements of Reusable Object-Oriented Software》一书(中文:设计模式:可复用面向对象软件设计),他们将设计模式利用于编程。因为名字太长,它被称为GOF书或四人帮的书。为什么要学习这些设计模式设计模式是针对常见软件设计问题的一组久经考验的解决方案。即便从未遇到过这些问题,学习设计模式依然很有价值,因为它教会咱们如何应用面向对象设计的准则解决各种问题。通过提供模式术语,设计模式还能够促成团队成员之间的沟通。设计模式的分类设计模式分为三大类: 创立模式 :提供对象创立机制,减少了现有代码的灵活性和重用性。构造模式 :解释了如何将对象和类组装成更大的构造,同时放弃构造的灵活性和效率。行为模式 :负责对象之间的无效沟通和职责调配。 创立设计模式创立模式提供了各种对象创立机制,减少了现有代码的灵活性和重用性。GoF 设计模式中定义了 5 种创立设计模式: 单例 :单例是一种创立设计模式,它确保一个类只有一个实例,并为这个实例提供一个全局拜访点。工厂 :工厂办法是一种创立型设计模式,它提供了在超类中创建对象的接口,同时容许子类更改创立的对象类型。形象工厂 :形象工厂是一种创立设计模式,它容许生成相干对象的类,而无需指定它们的具体类。构建器 :构建器是一种创立设计模式,可逐渐构建简单的对象。能够应用雷同的结构代码创建对象的不同类型和示意。原型 :原型是一种创立设计模式,它容许您复制现有对象,而不会使您的代码依赖于它们的类。 构造设计模式构造设计模式解释了如何将对象和类组装成更大的构造,同时放弃它们的灵活性和效率。GoF 设计模式中定义了 7 种构造设计模式: 适配器 :适配器是一种构造设计模式,它容许具备不兼容接口的对象进行通信。复合 :复合是一种构造设计模式,它容许您将对象组合成树结构,而后像解决单个对象一样应用这些构造。代理 : 代理是一种构造设计模式,容许提供占位符或代替另一个对象。应用代理,能够管制对原始对象的拜访,容许在申请被传递到原始对象之前或之后执行某些操作。享元 :应用享元,能够通过在多个对象之间共享状态的公共局部而不是将所有数据保留在每个对象中,将更多对象放入 RAM。外观 :外观是一种设计模式,它为库、框架或任何其余类集提供简化的接口。桥接 : 容许将一个大类或一组密切相关的类拆分为两个独立的层次结构:形象和实现,以独立开发。装璜器 :应用装璜器设计模式,能够通过将新行为搁置在蕴含新行为的非凡包装对象中来将新行为附加到对象。 行为设计模式行为模式波及算法和对象之间的职责调配。GoF 设计模式中定义了 11 种行为设计模式: 模板办法 :模板办法在超类中定义了算法的骨架,容许子类在不批改其构造的状况下笼罩特定步骤。中介者 :应用中介者,能够缩小对象之间的凌乱依赖。该模式限度了对象之间的间接通信,并迫使它们仅通过中介进行合作。责任链:责任 链容许您沿着处理程序链传递申请。收到申请后,每个处理程序决定是解决申请还是将其传递给链中的下一个处理程序。观察者 :观察者模式容许你定义一种机制来告诉多个对象他们正在察看的对象产生的事件。策略 :应用策略,能够定义一系列算法,将它们放入不同的类,并使它们的对象可调换。命令 :命令是一种行为设计模式,它将申请转换为蕴含无关它们的所有信息的独立对象。通过这种转换,您能够应用各种申请参数化办法,提早或排队申请的执行,并反对可吊销的操作。状态 :作为一种行为设计模式,状态容许对象在其外部状态发生变化时扭转其行为。看起来如同对象扭转了它的类。访问者 :应用访问者模式,您能够将算法与它们操作的对象离开。解释器 :解释器是一种行为设计模式 ,它定义了一种语言的语法示意,并提供了一个解释器来解决这种语法。迭代器 :一种称为迭代器的行为设计模式容许您遍历汇合的元素而不裸露它们的底层示意。备忘录 : 备忘录模式容许保留和复原对象的先前状态,而无需走漏其实现细节。 以上是23种模式的简介,在接下来一个月的文章中,咱们一起来具体学习这些设计模式。

September 18, 2022 · 1 min · jiezi

关于设计模式:设计模式-静态代理居然能解决这种问题我惊讶了

前言23种设计模式都会了吗?明天讲一下动态代理模式的实战场景。 代理模式给某一个对象提供一个代理对象,并由代理对象管制对原对象的援用。艰深的来讲代理模式就是咱们生存中常见的中介。 举个例子来阐明:如果说我当初想买一辆二手车,尽管我能够本人去找车源,做品质检测等一系列的车辆过户流程,然而这的确太节约我得工夫和精力了。我只是想买一辆车而已为什么我还要额定做这么多事呢?于是我就通过中介公司来买车,他们来给我找车源,帮我办理车辆过户流程,我只是负责抉择本人喜爱的车,而后付钱就能够了。 为什么要用代理模式? 中介隔离作用:在某些状况下,一个客户类不想或者不能间接援用一个委托对象,而代理类对象能够在客户类和委托对象之间起到中介的作用,其特色是代理类和委托类实现雷同的接口。 解决问题这篇文章借用 FreeSql.Cloud 开源我的项目的代码,解说代理模式的理论利用和收益,以及须要留神的中央。 FreeSql 是 c#.NET 功能强大的 ORM 框架,定义了 IFreeSql 接口,次要针对单个 ConnectionString 生产 ORM 操作对象。 跨多数据库的时候,不同的 ConnectionString 须要生成多个 IFreeSql 原始对象,如果是多租户场景每个租户 ConnectionString 都不雷同的状况下,就须要创立 N个 IFreeSql 原始对象。 FreeSql.Cloud 正是为了跨多数据库的问题而产生,它能够解决: 1、FreeSqlCloud 实现多库版 IFreeSql 接口,从应用习惯上放弃与单库版 IFreeSql 统一; 2、运行时,FreeSqlCloud 可动静增加或删除多个 ConnectionString 对应的 IFreeSql; 3、FreeSqlCloud 存储多租户 IFreeSql,最初沉闷工夫 > 10分钟的租户,开释对应 IFreeSql 缩小内存开销; 4、FreeSqlCloud 反对随时 Change 切换到对应的 IFreeSql 进行操作; 代理模式实战(一)Scoped FreeSqlCloud 多库版本IFreeSql 是一个极为严格、简略,且功能强大的接口,咱们始终在严格控制 API 泛滥增长,泛滥的 API 在后续革新时十分苦楚。 正因为它的简略定义,让咱们有机会应用到代理模式实现新的 IFreeSql 实现类 FreeSqlCloud。 public class FreeSqlCloud : IFreeSql{ IFreeSql CurrentOrm => ...; //请看前面 public IAdo Ado => CurrentOrm.Ado; public IAop Aop => CurrentOrm.Aop; public ICodeFirst CodeFirst => CurrentOrm.CodeFirst; public IDbFirst DbFirst => CurrentOrm.DbFirst; public GlobalFilter GlobalFilter => CurrentOrm.GlobalFilter; public void Transaction(Action handler) => CurrentOrm.Transaction(handler); public void Transaction(IsolationLevel isolationLevel, Action handler) => CurrentOrm.Transaction(isolationLevel, handler); public ISelect<T1> Select<T1>() where T1 : class => CurrentOrm.Select<T1>(); public ISelect<T1> Select<T1>(object dywhere) where T1 : class => Select<T1>().WhereDynamic(dywhere); public IDelete<T1> Delete<T1>() where T1 : class => CurrentOrm.Delete<T1>(); public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => Delete<T1>().WhereDynamic(dywhere); public IUpdate<T1> Update<T1>() where T1 : class => CurrentOrm.Update<T1>(); public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => Update<T1>().WhereDynamic(dywhere); public IInsert<T1> Insert<T1>() where T1 : class => CurrentOrm.Insert<T1>(); public IInsert<T1> Insert<T1>(T1 source) where T1 : class => Insert<T1>().AppendData(source); public IInsert<T1> Insert<T1>(T1[] source) where T1 : class => Insert<T1>().AppendData(source); public IInsert<T1> Insert<T1>(List<T1> source) where T1 : class => Insert<T1>().AppendData(source); public IInsert<T1> Insert<T1>(IEnumerable<T1> source) where T1 : class => Insert<T1>().AppendData(source); public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => CurrentOrm.InsertOrUpdate<T1>();}如上代码,若 CurrentOrm 返回值是原始 IFreeSql 对象,即会代理调用原始数据库 ORM 操作方法。办法不多,性能却弱小,代理模式利用起来就会很轻松。 ...

September 13, 2022 · 5 min · jiezi

关于设计模式:04创建型简单工厂模式

创立型:简略工厂模式目录介绍01.工厂模式介绍02.应用背景阐明03.模式构造介绍04.简略工厂模式05.简略工厂优缺点01.工厂模式介绍个别状况下,工厂模式分为三种更加细分的类型: 简略工厂、工厂办法和形象工厂。不过,在 GoF 的《设计模式》一书中,它将简略工厂模式看作是工厂办法模式的一种特例,所以工厂模式只被分成了工厂办法和形象工厂两类。实际上,在这三种细分的工厂模式中,简略工厂、工厂办法原理比较简单,在理论的我的项目中也比拟罕用。 而形象工厂的原理略微简单点,在理论的我的项目中绝对也不罕用。所以,明天解说的重点是前两种工厂模式。对于形象工厂,你略微理解一下即可。解说的重点也不是原理和实现,因为这些都很简略,重点还是带你搞清楚利用场景。 什么时候该用工厂模式?绝对于间接 new 来创建对象,用工厂模式来创立到底有什么益处呢?02.应用背景阐明思考一个简略的软件应用场景:一个软件系统能够提供多个外观不同的按钮(如圆形按钮、矩形按钮、菱形按钮等), 这些按钮都源自同一个基类,不过在继承基类后不同的子类批改了局部属性从而使得它们能够出现不同的外观。如果心愿在应用这些按钮时,不须要晓得这些具体按钮类的名字,只须要晓得示意该按钮类的一个参数,并提供一个调用不便的办法,把该参数传入办法即可返回一个相应的按钮对象,此时,就能够应用简略工厂模式。03.模式构造介绍Factory:工厂角色。工厂角色负责实现创立所有实例的外部逻辑Product:形象产品角色。形象产品角色是所创立的所有对象的父类,负责形容所有实例所共有的公共接口ConcreteProduct:具体产品角色。具体产品角色是创立指标,所有创立的对象都充当这个角色的某个具体类的实例。04.简略工厂模式首先,咱们来看,什么是简略工厂模式。通过一个例子来解释一下。在上面这段代码中,咱们依据配置文件的后缀(json、xml、yaml、properties),抉择不同的解析器(JsonRuleConfigParser、XmlRuleConfigParser……),将存储在文件中的配置解析成内存对象 RuleConfig。 public class RuleConfigSource { public RuleConfig load(String ruleConfigFilePath) { String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath); IRuleConfigParser parser = null; if ("json".equalsIgnoreCase(ruleConfigFileExtension)) { parser = new JsonRuleConfigParser(); } else if ("xml".equalsIgnoreCase(ruleConfigFileExtension)) { parser = new XmlRuleConfigParser(); } else if ("yaml".equalsIgnoreCase(ruleConfigFileExtension)) { parser = new YamlRuleConfigParser(); } else if ("properties".equalsIgnoreCase(ruleConfigFileExtension)) { parser = new PropertiesRuleConfigParser(); } else { throw new InvalidRuleConfigException( "Rule config file format is not supported: " + ruleConfigFilePath); } String configText = ""; //从ruleConfigFilePath文件中读取配置文本到configText中 RuleConfig ruleConfig = parser.parse(configText); return ruleConfig; } private String getFileExtension(String filePath) { //...解析文件名获取扩展名,比方rule.json,返回json return "json"; }}在“标准和重构”那一部分中,有讲到,为了让代码逻辑更加清晰,可读性更好,咱们要长于将性能独立的代码块封装成函数。 ...

September 12, 2022 · 2 min · jiezi

关于设计模式:百度工程师教你玩转设计模式工厂模式

作者 | 北极星小组 想要写好代码,设计模式(Design Pattern)是必不可少的基本功,设计模式是对面向对象设计(Object Oriented Design)中重复呈现的问题的解决方案,本篇介绍工厂模式(Factory Pattern)。 工厂模式属于创立型模式(Builder Pattern),提供了创建对象的最佳形式,在创建对象时,不会对客户端裸露对象的创立逻辑,而是通过应用独特的接口来创建对象。工厂模式利用的典型场景是,心愿可能创立一个对象,但创立过程比较复杂,心愿对外暗藏这些细节,比方:创建对象可能是一个pool里的,不是每次都凭空创立一个新的;对象创立时会有很多参数来决定如何创立出这个对象;创立一个对象有简单的依赖关系。 实现形式上,次要有简略工厂模式(Simple Factory Pattern)、工厂办法模式(Factory Method Pattern)、形象工厂模式(Abstract Factory Pattern)。 一、 简略工厂模式在文档解析场景中的利用在日常开发场景中,如果要创立的产品(被创立的对象类)不多,只有一个工厂类就能够实现,这种模式叫“简略工厂模式”。应用简略工厂模式的客户端(具体调用方)只须要传入须要创立产品类的参数,不须要关怀如何创建对象的逻辑,能够很不便地创立所需产品。 以Word2007类型文档解析场景为例:文档主体在document.xml文件,解析时依据内容构造维度别离创立Paragraph、Table、Draw等具体解析类。在解析流程中,如果间接结构对应解析类的对象应用,则会导致两者的耦合过重,能够应用“简略工厂模式”将解析类的理论创立工作推延到工厂类中。这也满足创立型模式中所要求的“创立与应用相拆散”的特点。 具体实现上包含以下几局部: 简略工厂(SimpleFactory):是简略工厂模式的外围,这里负责实现创立所有具体Parser实例的外部逻辑。形象产品(Product):是简略工厂创立的所有对象的父类,这里负责形容所有Parser实例共有的公共接口。具体产品(ConcreteProduct):是简略工厂模式的创立指标,这里负责创立具体的解析类。public class DocxPaser { //形象产品:所有Parser共有的公共接口 public interface IPaser { void process(string entity); } //具体产品:Paragraph Parser static class Paragraph implements IPaser { public void process(string entity) { System.out.println("解析 Paragraph..."); } } //具体产品:Table Parser static class Table implements IPaser { public void process(string entity) { System.out.println("解析 Table..."); } } //具体产品:Draw Parser static class Draw implements IPaser { public void process(string entity) { System.out.println("解析 Draw..."); } } final class Const { static final int ENTITY_PARAGRAPHP = 0; static final int ENTITY_TABLE = 1; static final int ENTITY_DRAW = 2; } //简略工厂:负责实现创立所有具体Parser实例的外部逻辑 static class ParserFactory { public static IPaser creatParser(int kind) { switch (kind) { case Const.ENTITY_PARAGRAPHP: return new Paragraph(); case Const.ENTITY_TABLE: return new Table(); case Const.ENTITY_DRAW: return new Draw(); } return null; } } // 简略应用示例 public static void main(String[] args) { //entity 对应document.xml 此处略去具体获取过程 ... //解析paragraph ParserFactory.creatParser(Const.ENTITY_PARAGRAPHP).process(entity) //解析table ParserFactory.creatParser(Const.ENTITY_TABLE).process(entity) //解析draw ParserFactory.creatParser(Const.ENTITY_DRAW).process(entity) ... }}二、工厂办法模式在自动化测试场景的利用在简略工厂模式中,调用方只须要传入须要创立的对象类参数,就能够取得一个须要的对象,而不必关怀这个对象的具体创立细节。在须要创立的对象类型较少,而且后续不再轻易减少的状况下简略工厂模式即可满足要求。然而针对须要创立的对象品种繁多,而且后续变更较为频繁的场景下,简略工厂模式有两个显著的问题: ...

September 9, 2022 · 3 min · jiezi

关于设计模式:03创建型单例设计不友好

创立型:单例设计不敌对目录介绍01.前沿简略介绍02.单例对OOP不敌对03.暗藏类之间依赖04.代码扩展性不敌对05.可测试性不敌对06.不反对有参构造函数07.有何代替解决方案01.前沿简略介绍只管单例是一个很罕用的设计模式,在理论的开发中,咱们也的确常常用到它,然而,有些人认为单例是一种反模式(anti-pattern),并不举荐应用。所以,就针对这个说法具体地讲讲这几个问题:单例这种设计模式存在哪些问题?为什么会被称为反模式?如果不必单例,该如何示意全局惟一类?有何代替的解决方案?02.单例对OOP不敌对OOP 的四大个性是封装、形象、继承、多态。单例这种设计模式对于其中的形象、继承、多态都反对得不好。为什么这么说呢?咱们还是通过 IdGenerator 这个例子来解说。 public class Order { public void create(...) { //... long id = IdGenerator.getInstance().getId(); //... }}public class User { public void create(...) { // ... long id = IdGenerator.getInstance().getId(); //... }}IdGenerator 的应用形式违反了基于接口而非实现的设计准则,也就违反了狭义上了解的 OOP 的形象个性。如果将来某一天,咱们心愿针对不同的业务采纳不同的 ID 生成算法。比方,订单 ID 和用户 ID 采纳不同的 ID 生成器来生成。为了应答这个需要变动,咱们须要批改所有用到 IdGenerator 类的中央,这样代码的改变就会比拟大。 public class Order { public void create(...) { //... long id = IdGenerator.getInstance().getId(); // 须要将下面一行代码,替换为上面一行代码 long id = OrderIdGenerator.getIntance().getId(); //... }}public class User { public void create(...) { // ... long id = IdGenerator.getInstance().getId(); // 须要将下面一行代码,替换为上面一行代码 long id = UserIdGenerator.getIntance().getId(); }}除此之外,单例对继承、多态个性的反对也不敌对。这里之所以会用“不敌对”这个词,而非“齐全不反对”,是因为从实践上来讲,单例类也能够被继承、也能够实现多态,只是实现起来会十分奇怪,会导致代码的可读性变差。不明确设计用意的人,看到这样的设计,会感觉莫名其妙。所以,一旦你抉择将某个类设计成到单例类,也就意味着放弃了继承和多态这两个强有力的面向对象个性,也就相当于损失了能够应答将来需要变动的扩展性。03.暗藏类之间依赖代码的可读性十分重要。在浏览代码的时候,咱们心愿一眼就能看出类与类之间的依赖关系,搞清楚这个类依赖了哪些外部类。通过构造函数、参数传递等形式申明的类之间的依赖关系,咱们通过查看函数的定义,就能很容易辨认进去。然而,单例类不须要显示创立、不须要依赖参数传递,在函数中间接调用就能够了。如果代码比较复杂,这种调用关系就会十分荫蔽。在浏览代码的时候,咱们就须要认真查看每个函数的代码实现,能力晓得这个类到底依赖了哪些单例类。04.代码扩展性不敌对单例类只能有一个对象实例。如果将来某一天,咱们须要在代码中创立两个实例或多个实例,那就要对代码有比拟大的改变。你可能会说,会有这样的需要吗?既然单例类大部分状况下都用来示意全局类,怎么会须要两个或者多个实例呢?实际上,这样的需要并不少见。咱们拿数据库连接池来举例解释一下。在零碎设计初期,咱们感觉零碎中只应该有一个数据库连接池,这样能不便咱们管制对数据库连贯资源的耗费。所以,咱们把数据库连接池类设计成了单例类。但之后咱们发现,零碎中有些 SQL 语句运行得十分慢。这些 SQL 语句在执行的时候,长时间占用数据库连贯资源,导致其余 SQL 申请无奈响应。为了解决这个问题,咱们心愿将慢 SQL 与其余 SQL 隔离开来执行。为了实现这样的目标,咱们能够在零碎中创立两个数据库连接池,慢 SQL 独享一个数据库连接池,其余 SQL 独享另外一个数据库连接池,这样就能防止慢 SQL 影响到其余 SQL 的执行。如果咱们将数据库连接池设计成单例类,显然就无奈适应这样的需要变更,也就是说,单例类在某些状况下会影响代码的扩展性、灵活性。所以,数据库连接池、线程池这类的资源池,最好还是不要设计成单例类。实际上,一些开源的数据库连接池、线程池也的确没有设计成单例类。05.可测试性不敌对单例模式的应用会影响到代码的可测试性。如果单例类依赖比拟重的内部资源,比方 DB,咱们在写单元测试的时候,心愿能通过 mock 的形式将它替换掉。而单例类这种硬编码式的应用形式,导致无奈实现 mock 替换。除此之外,如果单例类持有成员变量(比方 IdGenerator 中的 id 成员变量),那它实际上相当于一种全局变量,被所有的代码共享。如果这个全局变量是一个可变全局变量,也就是说,它的成员变量是能够被批改的,那咱们在编写单元测试的时候,还须要留神不同测试用例之间,批改了单例类中的同一个成员变量的值,从而导致测试后果相互影响的问题。06.不反对有参构造函数单例不反对有参数的构造函数,比方咱们创立一个连接池的单例对象,咱们没法通过参数来指定连接池的大小。针对这个问题,咱们来看下都有哪些解决方案。第一种解决思路是:创立完实例之后,再调用 init() 函数传递参数。须要留神的是,咱们在应用这个单例类的时候,要先调用 init() 办法,而后能力调用 getInstance() 办法,否则代码会抛出异样。具体的代码实现如下所示: ...

September 9, 2022 · 2 min · jiezi

关于设计模式:02创建型单例设计模式2

创立型:单例设计模式2目录介绍01.如何实现一个单例02.饿汉式实现形式03.懒汉式实现形式04.双重DCL校验模式05.动态外部类形式06.枚举形式单例07.容器实现单例模式01.如何实现一个单例介绍如何实现一个单例模式的文章曾经有很多了,但为了保障内容的完整性,这里还是简略介绍一下几种经典实现形式。概括起来,要实现一个单例,咱们须要关注的点无外乎上面几个: 构造函数须要是 private 拜访权限的,这样能力防止内部通过 new 创立实例;思考对象创立时的线程平安问题;思考是否反对提早加载;思考 getInstance() 性能是否高(是否加锁)。02.饿汉式实现形式饿汉式的实现形式比较简单。在类加载的时候,instance 动态实例就曾经创立并初始化好了,所以,instance 实例的创立过程是线程平安的。不过,这样的实现形式不反对提早加载,从名字中咱们也能够看出这一点。具体的代码实现如下所示: //饿汉式单例类.在类初始化时,曾经自行实例化 public class Singleton { //static润饰的动态变量在内存中一旦创立,便永恒存在 private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; } }代码剖析 饿汉式在类创立的同时就曾经创立好一个动态的对象供零碎应用,当前不再扭转,所以天生是线程平安的。其中 instance = new Singleton()能够写成: static { instance = new Singleton(); }有人感觉这种实现形式不好 因为不反对提早加载,如果实例占用资源多(比方占用内存多)或初始化耗时长(比方须要加载各种配置文件),提前初始化实例是一种浪费资源的行为。最好的办法应该在用到的时候再去初始化。不过,我集体并不认同这样的观点。如果初始化耗时长,那咱们最好不要等到真正要用它的时候,才去执行这个耗时长的初始化过程,这会影响到零碎的性能(比方,在响应客户端接口申请的时候,做这个初始化操作,会导致此申请的响应工夫变长,甚至超时)。采纳饿汉式实现形式,将耗时的初始化操作,提前到程序启动的时候实现,这样就能防止在程序运行的时候,再去初始化导致的性能问题。如果实例占用资源多,依照 fail-fast 的设计准则(有问题及早裸露),那咱们也心愿在程序启动时就将这个实例初始化好。如果资源不够,就会在程序启动的时候触发报错(比方 Java 中的 PermGen Space OOM),咱们能够立刻去修复。这样也能防止在程序运行一段时间后,忽然因为初始化这个实例占用资源过多,导致系统解体,影响零碎的可用性。03.懒汉式实现形式有饿汉式,对应地,就有懒汉式。懒汉式绝对于饿汉式的劣势是反对提早加载。具体的代码实现如下所示: //懒汉式单例类.在第一次调用的时候实例化本人 public class Singleton { //公有的构造函数 private Singleton() {} //公有的动态变量 private static Singleton single=null; //裸露的私有静态方法 public static Singleton getInstance() { if (single == null) { single = new Singleton(); } return single; } }代码剖析 ...

September 8, 2022 · 2 min · jiezi

关于设计模式:史上最全讲解单例模式以及分析源码中的应用

1、单例模式介绍所谓类的单例设计模式,就是采取肯定的办法保障在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个获得其对象实例的办法(静态方法)。 比方Hibernate 的SessionFactory,它充当数据存储源的代理,并负责创立Session 对象。SessionFactory 并不是轻量级的,个别状况下,一个我的项目通常只须要一个SessionFactory 就够,这是就会应用到单例模式。 2、单例模式的品种饿汉式(动态常量)饿汉式(动态代码块)懒汉式(线程不平安)懒汉式(线程平安,同步办法)懒汉式(线程平安,同步代码块)双重查看动态外部类枚举1、饿汉式(动态常量)步骤: 构造方法私有化内的外部创建对象向外裸露一个动态的公共办法public class Singleton01 { private static final Singleton01 INSTANCE = new Singleton01(); /** * 构造方法私有化,避免new */ private Singleton01(){ } /** * 提供一个私有的静态方法,返回实例对象 * @return INSTANCE */ public static Singleton01 getINSTANCE() { return INSTANCE; } public static void main(String[] args) { Singleton01 instance1 = Singleton01.getINSTANCE(); Singleton01 instance2 = Singleton01.getINSTANCE(); System.out.println(instance1 == instance2); System.out.println("instance1.hashCode = " + instance1.hashCode()); System.out.println("instance2.hashCode = " + instance2.hashCode()); }}优缺点: ...

September 5, 2022 · 5 min · jiezi

关于设计模式:面试官工厂方法模式是什么

真正的巨匠永远怀着一颗学徒的心吃不了学习的苦就要吃生存的苦文章继续更新,能够微信搜寻【小奇JAVA面试】第一工夫浏览,回复【材料】更有我为大家筹备的福利哟!回复【我的项目】有我为大家筹备的一些我的项目源码。回复【简历模板】有我为大家筹备的简历模板。 前言明天的电子缝纫机厂仍旧是热气腾腾,小伙子们为了娶媳妇都干劲十足,把脚下的缝纫机踏板踩的直冒烟,就在我聚精会神干活达到一种人机合一的状态时,忽然厂房的门从里面推开了,来了一位新共事,本着不是本人的冷落就必须得看的准则,我和大家一样把眼光缓缓的移向门口。 咦~,这人怎么看着这么眼生呢?这不是网红电瓶哥吗,他怎么可能来打工呢。 趁中午吃饭之际,我找到电瓶哥。 我:“电瓶哥,你不是号称不可能打工的嘛,怎么也来这里打工了啊。” 电瓶哥:“我没有来打工啊,我是来干活的。” 我:“你特么的竟让我无言以对。。。是谁说通你来打工的呀,我挺好奇的。” 电瓶哥:“没有人劝我,是我看到了村口的广告,我筹备挣钱找个婆娘。” 我:“这广告成果真不错呀,通俗易懂又有诱惑力。” 就在这时我的手机忽然响了。 我:“喂,这又是谁啊!” 对方:“我,还是昨天给你打电话面试的,你当初不便吗,咱们再聊会。” 我:“不便,只有是上班时间接电话我都不便。” 一、面试面试官:咱们明天来聊聊工厂办法模式吧,你说一说你对工厂办法模式的了解? 我:工厂办法模式是简略工厂模式的延长,它继承了简略工厂模式的长处,同时还补救了简略工厂模式的缺点。 面试官:你能说说工厂办法模式比简略工厂模式好在哪里吗? 我:在工厂办法模式中咱们工厂类中的逻辑是依据传进来的参数来进行对应的,就是如果你想买苹果了,那你在工厂类中就得有依据苹果参数生成苹果实例的判断逻辑,当你忽然想吃菠萝了,如果工厂类中之前没有这一块的逻辑,你就得去工厂类中减少这一块的逻辑了,这样你就会频繁的批改工厂类中的代码,这样就不合乎开闭准则了。 而工厂办法模式在工厂类和产品之间减少了一个具体工厂,咱们具体的产品通过具体的工厂来生产,不须要批改工厂类中的逻辑。 例如咱们之前是“真甜呀果园”,你想吃苹果了间接给咱们厂里打电话咱们就给你邮寄一箱苹果。然而咱们当初业务扩大了,咱们开始养家禽了,如果你想吃鸡也能够给咱们打电话,然而这个时候还给“真甜呀果园”打电话就有点不适合了。 所以我当初成立了一个奇哥团体,你想吃什么间接给奇哥团体打电话就行,如果你想吃苹果,你就打电话给奇哥团体,而后奇哥团体给上司的“真甜呀果园”打电话给你邮寄一箱苹果,如果你想吃鸡,你也给奇哥团体打电话,而后奇哥给上司的“真香呀鸡圈”打电话给你邮寄一只鸡。 面试官:那你说一下工厂办法模式有哪些角色吧! 1、Product(形象产品):他是定义产品的接口,他在这里相当于装水果的箱子,或者装鸡的笼子。 2、ConcreteProduct(具体产品):他实现了形象产品接口,他在这里相当于苹果或者鸡。 3、Factory(形象工厂):他在这里相当于奇哥团体,他用于接管客户的电话,而后给客户一箱水果或者一笼鸡。 4、ConcreteFactory(具体工厂):他在这里相当于“真甜呀果园”或者“真香呀鸡圈”,他负责接管团体的电话而后给团体相应的产品。 面试官:那你能够写一下具体的代码来形容一下工厂办法模式吗? 1、首先定义一个箱子接口,这个代表形象产品角色 public interface Box { public void show();}2、而后定义一个苹果类,这个代表具体产品 public class Apple implements Box { @Override public void show() { System.out.println("买了一箱苹果"); }}3、而后定义一个奇哥团体类,这个代表形象工厂 public interface FactoryQG { public void show(String name); //形象工厂办法}4、而后定义一个“真香呀”类,这个代表具体工厂 public class Zxy implements FactoryQG { Box box = null; @Override public void show(String name) { if(name.equals("苹果")){ box = new Apple(); box.show(); System.out.println("真香呀果园苹果,50元一箱"); } }}5、最初测试 ...

August 25, 2022 · 1 min · jiezi

关于设计模式:面试官设计模式是什么

真正的巨匠永远怀着一颗学徒的心让石头裂开的不是最初一击,而是后面的99次击打文章继续更新,能够微信搜寻【小奇JAVA面试】第一工夫浏览,回复【材料】更有我为大家筹备的福利哟!回复【我的项目】有我为大家筹备的一些我的项目源码。回复【简历模板】有我为大家筹备的简历模板。 @[TOC] 前言明天我将头发梳成小孩儿样,穿上一身帅气西装,并不是我闲的某个中央疼了,而是明天我又要去面试了。 七月的京城最高温度曾经靠近40摄氏度,但还是不可能捂热我那被面试官回绝后凉透的心。顶着炎炎烈日我来到了约定的面试地点,看着背后这雄伟的修建,感觉这次面试又稳了(稳挂)。 进入大厦被接待人员领到指定的会议室,接待人员说他们李总正在散会,一会过去给我面试,顺便给我倒了一杯水,让我稍作休憩。 就在我想着一会怎么跟面试官吹牛的时候我听见了“咚咚咚”高跟鞋的声音正在由远及近的传来,我迟缓的转动着手里的纸杯,依据声音专一的剖析着:“女、175、98斤、粉色”,“咔哒”一声门开了,我扭头看向门口心里窃喜,没有什么能够瞒过我的耳朵,如果有那就是上学时老师讲的每一节课。 一、面试面试官:我看你简历上写的精通设计模式,那你能说一下设计模式是什么吗? 我:我的了解设计模式就是一些模板,在咱们开发程序的时候咱们能够依据不同的业务场景抉择应用不同的模板来开发,这样就不须要咱们本人从新设计一套货色了,省时省力。 面试官:设计模式是软件畛域首先提出来的吗? 我:并不是软件畛域首先提出的,设计模式起源于修建畛域,他们将前人教训进行总结,而后为前人间接提供成熟的解决方案。 面试官:那你说一下设计模式的定义吧! 我:设计模式是在特定环境下为解决某一通用软件设计问题提供的一套定制的解决方案,该计划形容了对象和类之间的相互作用。 面试官:设计模式能够分为几类呢,别离是什么? 我:设计模式能够分为三类,别离是创立型、结构型和行为型。 面试官:说了这么多,那设计模式有哪些长处呢? 我:设计模式交融了前辈的很多教训,并且总结成以肯定规范的模式提供给开发人员应用,这样开发人员能够更加疾速、成熟的开发出符合要求的零碎。 面试官:那你晓得什么是面向对象吗? 我:晓得呀,就是面向你呗(撩拨ing) 面试官:别贫,面试通过你才有资格贫,说一下面向对象设计有哪些准则吧 我:面向对象有七个设计准则,别离是繁多职责准则、开闭准则、里氏代换准则、依赖倒转准则、接口隔离准则、合成复用准则、迪米特法令。 面试官:能具体介绍一下这七个设计准则吗? 繁多职责准则:一个对象应该只蕴含繁多的职责,并且该职责被残缺地封装在一个类中。 开闭准则:软件实体该当对扩大凋谢,对批改敞开。 里氏代换准则:所有援用基类的中央必须能通明地应用其子类的对象。 依赖倒转准则:高层模块不应该依赖低层模块,它们都应该依赖形象。形象不应该依赖于细节,细节应该依赖于形象。 接口隔离准则:客户端不应该依赖那些它不须要的接口。 合成复用准则:优先应用对象组合,而不是通过继承来达到复用的目标。 迪米特法令:每一个软件单位对其余单位都只有起码的常识,而且局限于那些与本单位密切相关的软件单位。 面试官:答复的十分好,你还有什么想问我的吗? 我:有,我听力十分好,我刚刚听进去有粉色的存在,请问我听对否? 面试官:哎呀~流氓。。。 二、总结这里的相干内容还没有整顿结束,文章前面继续更新,倡议珍藏。 文章中波及到的命令大家肯定要像我一样每个都敲几遍,只有在敲的过程中能力发现自己对命令是否真正的把握了。 如果感觉我的文章还不错的话就点个赞吧,另外能够微信搜寻【小奇JAVA面试】第一工夫浏览,回复【材料】更有我为大家筹备的福利哟!回复【我的项目】有我为大家筹备的一些我的项目源码。回复【简历模板】有我为大家筹备的简历模板。

August 23, 2022 · 1 min · jiezi

关于设计模式:设计模式之享元模式

本文通过优化买票的反复流程来阐明享元模式,为了加深对该模式的了解,会以String和根本数据类型的包装类对该模式的设计进一步阐明。 读者能够拉取残缺代码到本地进行学习,实现代码均测试通过后上传到码云。 一、引出问题鉴于小王之前的优质体现,老王决定带小王进来游览一下,但在火车站买票时却陷于了长长的队伍。 老王留神到,每次售票员卖票时都从新走一遍卖票的所有流程,很显著,如果始发地和目的地如果一样的成人票和儿童票是能够复用流程的,如果复用的话就能够大大提高卖票效率。 二、概念和应用下面所说的复用流程实际上就是享元模式的设计思维,它是构造型设计模式之一,它通过共享数据使得雷同对象在内存中仅创立一个实例,以升高零碎创建对象实例的性能耗费。 享元模式蕴含三个角色: (1)形象享元Flyweight类:享元对象形象基类或接口。 (2)具体享元ConcreteFlyweight类:实现形象享元类。 (3)享元工ctory类:厂FlyweightFa享元模式的外围模块,负责管理享元对象池、创立享元对象,保障享元对象能够被零碎适当地共享。 当一个客户端对象调用一个享元对象的时候,享元工厂角色会查看零碎中是否曾经有一个符合要求的享元对象,如果已有,享元工厂角色就提供这个已有的享元对象;如果没有就创立一个。 老王基于享元模式开发了一套卖票零碎,如果终点和起点一样,成人票和儿童票就能够复用一套流程。 形象享元类: /** * 形象享元类 */public interface Ticket { //显示票价,参数为列车类型 public void showPrice(String type);}具体享元实现类: /** * 享元实现类 * @author tcy * @Date 11-08-2022 */public class ConcreteTicket implements Ticket{ String from; String to; public ConcreteTicket(String from,String to){ this.from = from; this.to = to; } @Override public void showPrice(String type) { if(type.equals("adult")){ System.out.println("从"+from+"到"+to+"的成人票价为200元"); }else{ System.out.println("从"+from+"到"+to+"的儿童票价为100元"); } }}享元工厂类: /** * 享元工厂 * @author tcy * @Date 11-08-2022 */public class TicketFactory { static Map<String,Ticket> map= new ConcurrentHashMap< String,Ticket >(); public static Ticket getTicket(String from,String to){ String key = from+to; if(map.containsKey(key)){ System.out.println("应用缓存"+key); return map.get(key); }else{ System.out.println("创建对象"+key); Ticket ticket = new ConcreteTicket(from,to); map.put(key, ticket); return ticket; } }}客户端调用: ...

August 16, 2022 · 2 min · jiezi

关于设计模式:设计模式单例模式

1.1 单例模式介绍所谓类的单例设计模式,就是采取肯定的办法保障在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个获得其对象实例的办法(静态方法)。比方 Hibernate 的 SessionFactory,它充当数据存储源的代理,并负责创立 Session 对象。SessionFactory 并不是轻量级的,个别状况下,一个我的项目通常只须要一个 SessionFactory 就够,这是就会应用到单例模式。 单例模式八种形式 饿汉式 ( 动态常量 )饿汉式(动态代码块)懒汉式(线程不平安)懒汉式(线程平安,同步办法)懒汉式(线程平安,同步代码块)双重查看动态外部类枚举1.2 饿汉式(动态常量)利用实例 步骤如下: 结构器私有化 (避免 new)类的外部创建对象向外裸露一个动态的公共办法 getInstance代码实现 public class SingletonDemo01 { public static void main(String[] args) { Singleton01 instance01 = Singleton01.getInstance(); Singleton01 instance02 = Singleton01.getInstance(); System.out.println(instance01 == instance02); // true System.out.println("instance01 hashcode=" + instance01.hashCode()); System.out.println("instance02 hashcode=" + instance02.hashCode()); }}/** * 饿汉式--动态常量 */class Singleton01 { // 1.构造方法私有化,内部不能 new private Singleton01() { } // 2.定义动态变量 public final static Singleton01 instance = new Singleton01(); // 3.向外裸露一个静态方法 public static Singleton01 getInstance() { return instance; }}优缺点阐明 ...

August 15, 2022 · 4 min · jiezi

关于设计模式:设计模式之组合模式

本文通过老王和小王探讨书房、书架、各类书的治理问题,引出结构型设计模式家族中的一个重要成员——组合模式,本文会给予两种组合模式的典型代码实现,为了加深了解会在第三局部利用中介绍组合模式在源码中的理论使用,最初总结该设计模式学习后的一些思考。 读者能够拉取残缺代码到本地进行学习,实现代码均测试通过后上传到码云。 一、引出问题上篇文章中老王给小王买车当前,小王对老王感激涕零,看着老王凌乱的书房,小王提出要帮忙老王整顿整顿他的书架。 小王开始了他的剖析。老王平时博览群书,中文、英文、梵文...每个语种占满了书架,而每个语种中又分经济学、计算机学、社会学等等类目。这是典型的分层次结构,将语种比作是图书的子类,类目是语种的子类构造划分。 将图书、语种、类目都看做是组织构造,他们之间没有继承关系,而是一个树形构造,能够更好的实现治理操作。 二、概念与应用实际上,小王提出来的设计思路正是结构型设计模式中的组合模式,咱们首先看一下组合模式的相干概念,组合模式(Composite Pattern),又叫局部整体模式,它创立了对象组的树形构造,将对象组合成树状构造以示意“整体-局部”的档次关系。组合模式根据树形构造来组合对象,用来示意局部以及整体档次。 组合模式使得用户对单个对象和组合对象的拜访具备一致性,即:组合能让客户以统一的形式解决个别对象以及组合对象。 用大白话解释也就是,在理论利用中将所有图书按照树形模式进行组合,老王寻找书籍时,无论是拜访某一类书还是某一个语种的书,应用同样的姿态即可,保障了拜访的一致性。 在该模式中应该是有三个角色: 1、Root :这是组合中对象申明接口,在适当状况下,实现所有类共有的接口默认行为,用于拜访和治理Root 子部件, Root 能够是抽象类或者接口。 2、Branches:非叶子节点用于存储子部件,在Root接口中实现了 子部件的相干操作。 2、Leaf : 在组合中示意叶子节点,叶子节点没有子节点。 小王剖析的有条有理,老王提出来了他的疑难。 当我按语种查找还是按类目查找是应用的办法有时候是不一样的,如果你把所有办法都定义在Root中,在语种或者类目中实现中是无意义的,而且这违反了接口隔离准则。 小王感觉说的对也不对,如果我改成不在Root中定义,那么我在客户端调用的时候就须要判断是枝还是叶了,减少了繁冗的逻辑判断,而且相比另外一种变得不通明了,依赖倒置准则也没有恪守。 两种形式仿佛都有缺点,小王陷入了纠结不晓得该如何取舍,老王提出了他的一些见解,没有任何一个设计模式是齐全没有毛病的,两种都有各自的益处,在理论的使用中依据条件进行取舍,而正确抉择的前提就是要对所有的设计模式充沛的把握。 下面两种就对应组合模式中的两个大分类、①通明组合模式、平安组合模式。 ①通明组合模式把所有的公共办法都定义在Root中,这样做的益处就是客户端无需分辨是叶子节点(Leaf)和树枝节点(Branches),他们具备完全一致的接口;毛病是叶子节点(Leaf)会继承失去一些它所不须要(治理子类操作的办法)的办法,这与设计模式接口隔离准则相违反。 ②平安组合模式的益处是接口定义职责清晰,合乎设计模式繁多职责准则和接口隔离准则;毛病是客户须要辨别树枝节点(Branches)和叶子节点(Leaf),这样能力正确处理各个档次的操作,客户端依赖形象(Root),违反了依赖倒置准则。 咱们把两种的形式实现,读者比照他们之间的区别。 平安模式 Root(根节点): /** * @author tcy * @Date 08-08-2022 */public abstract class RootBook { protected String name; public RootBook(String name) { this.name = name; } public abstract String operation();}Branches(树枝节点) /** * @author tcy * @Date 08-08-2022 */public class BranchesLanguages extends RootBook { private List<RootBook> roots; public BranchesLanguages(String name) { super(name); this.roots = new ArrayList<RootBook>(); } public String operation() { StringBuilder builder = new StringBuilder(this.name); for (RootBook component : this.roots) { builder.append("\n"); builder.append(component.operation()); } return builder.toString(); } public boolean addChild(RootBook component) { return this.roots.add(component); } public boolean removeChild(RootBook component) { return this.roots.remove(component); } public RootBook getChild(int index) { return this.roots.get(index); }}Leaf(叶子节点) ...

August 9, 2022 · 3 min · jiezi

关于设计模式:设计模式之桥接模式

本文通过老王和小王买车,引出设计模式中的结构型设计之桥接模式,接着阐明设计型模式的概念和代码实现,为了加深了解,会阐明适配器设计模式在JDBC中的利用,最初谈谈桥接模式和适配器模式的总结。 读者能够拉取残缺代码到本地进行学习,实现代码均测试通过后上传到码云。 一、引出问题老王和小王去飞驰4S店买车,飞驰4S店的各种品牌型号目不暇接,老王想试驾飞驰E、小王想试驾飞驰G,并且提出两种飞驰型号的各种色彩都想体验一把,这让店小二犯了难,两两组合就是很多种,4S店压根放不下。 无奈店小二求救经理,经理出了一个留神:将飞驰E和G开的品牌形象进去,将色彩也形象进去,通过品牌和色彩的组合代替继承关系,缩小了色彩和品牌的耦合,且缩小了车的个数,只须要两台就够了。 果然经理不愧是经理。 经理所说的其实就是桥接模式。这种模式波及到一个作为桥接的接口,使得实体类的性能独立于接口实现类。这两种类型的类可被结构化扭转而互不影响。 二、概念与应用咱们看一些概念:桥接(Bridge)是用于把抽象化与实现化解耦,使得二者能够独立变动。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接构造,来实现二者的解耦。 在该模式中应该波及到四个角色: ①实现类接口(Implementor):定义实现角色的接口,供扩大抽象化角色应用,例如形象出飞驰品牌benz 能够扩大出 benzE benzG ②具体实现角色(ConcreteImplementor):实现类的具体实现,例如各种飞驰品牌 ③抽象化(Abstraction)角色:定义一个抽象类,其中援用了实现化角色(想要组合),例如汽车产品 ④扩大抽象化(RefinedAbstraction)角色:抽象化角色子类,实现父类办法,且通过组合关系调用实现化角色中的业务办法,例如具体飞驰产品,红色飞驰、红色飞驰 依据该模式的定义,咱们将飞驰品牌形象进去,而后各品牌有各自的实现,每个色彩的车把车品牌组合进来,在客户端中每个相机类型和相机品牌都能两两组合。 咱们看具体的代码实现: 实现类接口: /** * 飞驰品牌类 * @author tcy * @Date 05-08-2022 */public interface BenzBrand { void showInfo();}具体实现角色1: /** * @author tcy * @Date 05-08-2022 */public class BenzE implements BenzBrand{ @Override public void showInfo() { System.out.print("【飞驰E】色彩是:"); }}具体实现角色2: /** * @author tcy * @Date 05-08-2022 */public class BenzG implements BenzBrand{ @Override public void showInfo() { System.out.print("【飞驰G】色彩是:"); }}抽象化角色: ...

August 5, 2022 · 3 min · jiezi

关于设计模式:设计模式之适配器模式

本文通过老王应用纸质书籍浏览小王应用电子书籍的故事,具体阐明设计模式中的结构型设计模式之适配器模式,别离对对象适配器和类适配器代码实现,最初为了加深了解,会列举适配器设计模式在JDK和Spring源码中的利用。 读者能够拉取残缺代码到本地进行学习,实现代码均测试通过后上传到码云。 一、引出问题自从小王被老王赶出家门当前,老王过了几天舒心的日子,在家里的书架上买了许许多多的纸质书。 有一天,小王过够了野人生存回来了,小王也是一个喜爱读书的人,然而小王不喜爱纸质书,就要求老王将这些书换成电子版。 老王立马就不开心了,这是我不晓得破费多少个日夜才设计好的书架,给你换成电子版的不仅要花费我大量的精力扭转原有书架的构造,再想找我想看的书得有多难,而且老李来了想看纸质版怎么办,我还要再换回去吗? 小王随即想到了一种解决思路:这些书当初合乎你的格调,应该设计一种模式,让这些书也能合乎我的需要,让咱们俩能够在一起读书,既不扭转你的书架构造,又能扩大它的性能。 老王称心的点了拍板,你说的不错,这实际上就是结构型设计模式中的适配器模式。 二、概念与应用援用Gof中对适配器设计模式的概念:将一个类的接口转化成客户心愿的另一个接口,因为接口不兼容而不能一起工作的类能够一起工作。 很显然,在适配器设计模式中应该有三个角色。 指标类:Target,该角色把其余类转换为咱们冀望的接口,能够是一个抽象类或接口,也能够是具体类。 被适配者类(源): Adaptee ,原有的接口,也是心愿被适配的接口。 适配器: Adapter, 将被适配者和指标抽象类组合到一起的类。在咱们的理论案例中,老王的纸质书很显著应该是属于被适配者,小王的电子版就是指标类,适配器应该是能调用老王的纸质书,并应用一些相干的业务办法转化成电子版,比方调用老王书之前买一个扫描仪,在老王书调进去当前扫描书籍。 既然适配器中要调用老王的纸质书,调用它的办法应该是有两种实现形式。 一是间接继承老王,那样就能够间接调用老王的办法了。 二是在适配器中创立老王的对象,而后再调用老王的办法。 这其实对应了适配器的两种形式,依据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。 咱们先看类适配器实现形式: 被适配者类: /** * 源对象 * @author tcy * @Date 04-08-2022 */public class AdapteePaperReading { public void readPaper(){ System.out.println("这是老王读的纸质书...(被适配者办法)"); }}指标对象: /** * 指标对象 */public interface TargetOnlineReading { public void ReadOnline();}适配器: /** * @author tcy * @Date 04-08-2022 */public class Adapter extends AdapteePaperReading implements TargetOnlineReading{ @Override public void ReadOnline() { System.out.println("买一个扫描仪..."); readPaper(); System.out.println("拿到纸质书扫描为电子书..."); }}客户端: ...

August 4, 2022 · 2 min · jiezi

关于设计模式:设计模式之代理模式

本文由老王出租房子引出——代理设计模式,将从最简略的动态代理实现开始,后延长应用jdk实现动静代理,最初扩大到Cglib实现动静代理。为了更深刻了解代理模式,咱们会对理论利用中的典型案例进行介绍,包含在Spring和Mybatis中的利用。 读者能够拉取残缺代码到本地进行学习,实现代码均测试通过后上传到码云。 一、引出问题上篇文章老王和小王组装电脑尽管完满完结了,然而老王和小王的争吵却并没有完结。老王决定将小王扫地出门,并把小王住的房子出租,租金用来补救游戏本的花销。 老王破费很大的功夫,搞清楚了各种租房平台的规定并公布了房源信息,接着街坊揭示他:房子租出去并不代表躺着收租金了,有一天租客提出一些额定的要求,在合同容许的范畴内,你也要尽量满足他们(为了便于了解,事实当然不存在啦),房子租出去后物业有问题你还要和物业协调。 老王开始思考,如果我直租给租客,会面临两个问题: ①我须要理解租房的全过程,我本人的事和租房的事重大的耦合了。 ②租客提出的一些要求我不得不染指到其中,我不得不扭转我本人的行程安顿。 我应该想到一种方法, 第一点,将业务和性能解耦,业务层专一业务,比方网络接口申请,业务层只须要晓得该调哪个接口申请办法,而不须要晓得这个接口申请是如何发动网络申请的。 第二点,创立一个切面,在这个切面中减少一些通用的附加操作,比方注解解析,日志上报等,防止这些通用操作在每个接口办法都要写一遍。 老王灵感一闪:我能够给我的房子找一个一个代理,以管制对这个房子的治理。即通过代理治理房子.这样做的益处是:能够在指标实现的根底上,加强额定的性能操作,即扩大指标的性能。 这实际上就是动态代理。 二、动态代理代理模式:为一个对象提供一个替身,以管制对这个对象的拜访。即通过代理对象拜访指标对象.这样做的益处是:能够在指标对象实现的根底上,加强额定的性能操作,即扩大指标对象的性能。 也即在动态代理中应该有三个角色: ①代理对象,生产端通过它来拜访理论的对象(中介) ②理论被代理的对象(老王房子) ③一组能够被代理的行为的汇合,通常是一个接口(老王和中介之间的约定事件) 老王与中介的约定接口: /** * 代理行为的汇合(接口) * @author tcy * @Date 02-08-2022 */public interface HostAgreement { // 房子出租 void rent();}理论对象类(老王): /** * 指标对象 * @author tcy * @Date 02-08-2022 */public class Host implements HostAgreement { /** * 指标对象的原始办法 */ @Override public void rent() { System.out.println(" 这个房子要出租..."); }}代理类(中介): /** * 理论对象的代理 * @author tcy * @Date 02-08-2022 */public class HostProxy implements HostAgreement { // 指标对象,通过接口来聚合 private HostAgreement target; //结构器 public HostProxy(HostAgreement target) { this.target = target; } @Override public void rent() { System.out.println("房子出租前,装修一下...."); target.rent(); System.out.println("房子出租后,与物业协调....");//办法 }}客户类: ...

August 3, 2022 · 3 min · jiezi

关于设计模式:设计模式之工厂方法和抽象工厂

全网最具体的工厂设计模式,本文次要是创立型设计模式中的工厂办法和形象工厂,先由传统实现形式引出问题,接着对代码改良到简略工厂,后扩大到工厂办法,最初是形象工厂模式,文中包含概念了解和相干实现代码。 读者能够拉取残缺代码本地学习,实现代码均测试通过上传到码云 一、引出问题如果有一个客户老王,须要购买产品,产品别离是A、B、C。 如果用传统办法实现,别离定义A、B、C三个类,再别离创立他们所属的办法。 在客户对象中再别离调用他们的办法。 Product ClientProduct(String orderType) { Product product; if (orderType.equals("A")) { product = new ProductA(); } else if (orderType.equals("B")) { product = new ProductB(); } else if (orderType.equals("B")) { product = new ProductC(); } // product制作过程 product.common(); return product;}如果咱们须要再减少一个产品D,就须要判断再减少一个分支,而后在分支外面创立产品对象,调用产品D的办法。 这样代码的维护性是极差的,查看咱们的软件设计七大准则,很显著,这违反了开闭准则、依赖倒置准则. 如果又有个客户小王,那么小王也必须依赖每个产品类,这样就显得繁杂。 二、简略工厂(动态工厂)简略工厂(动态工厂)模式就利用而生了。 如果咱们将产品A、B、C形象进去一个父类,再专门创立一个工厂类,在客户购买产品时,只须要传入产品的类型,由工厂去创立产品。 简略工厂模式中蕴含如下角色: Factory:工厂角色 工厂角色负责实现创立所有实例的外部逻辑。 Product:形象产品角色 形象产品角色是所创立的所有对象的父类,负责形容所有实例所共有的公共接口。 ConcreteProduct:具体产品角色 具体产品角色是创立指标,所有创立的对象都充当这个角色的某个具体类的实例。 看看咱们对原始实现形式后的代码。 产品形象父类: /** * @author tcy * @Date 28-07-2022 */public class Product { public void common(){ System.out.println("这是产品父类公共办法..."); }}产品A: ...

July 28, 2022 · 3 min · jiezi

关于设计模式:设计模式概述

成为一名优良的软件开发工程师,设计模式的重要性显而易见,本章节是对设计模式的前置常识概述,波及概念性较大,读者可在设计模式学习过程中参阅本文档。 在第一章节,次要介绍软件设计的七大准则,接着在第二章咱们简要介绍设计模式的三种分类,让咱们站在肯定的高度对设计模式有整体的把握,第三章UML类图帮忙咱们更好的看懂设计模式的代码。 一、软件设计七大准则无论是在咱们学习设计模式的过程中,还是日常的开发过程中,都要遵循一套对立的软件设计准则。 在常见的设计准则中,一共是7 种设计准则,它们别离为开闭准则、里氏替换准则、依赖倒置准则、繁多职责准则、接口隔离准则、迪米特法令和合成复用准则。 各种各样的准则最终目标只有一句话,也是软件开发人员听过的最多的一句话:高内聚、低耦合,进步复用性、可扩展性、可维护性。 设计准则一句话演绎目标开闭准则对扩大凋谢,对批改敞开升高保护带来的新危险依赖倒置准则高层不应该依赖低层,要面向接口编程更利于代码构造的降级扩大繁多职责准则一个类只干一件事,实现类要繁多便于了解,进步代码的可读性接口隔离准则一个接口只干一件事,接口要精简繁多性能解耦,高聚合、低耦合迪米特法令不该晓得的不要晓得,一个类应该放弃对其它对象起码的理解,升高耦合度只和敌人交换,不和陌生人谈话,缩小代码臃肿里氏替换准则不要毁坏继承体系,子类重写办法性能产生扭转,不应该影响父类办法的含意避免继承泛滥合成复用准则尽量应用组合或者聚合关系实现代码复用,少应用继承升高代码耦合这些准则在咱们开发过程中或多或少的都有体现,比方在咱们的我的项目中业务层总是定义Service接口,在Impl中实现具体的逻辑,很多开发只是照葫芦画瓢,却并不知道为什么要这样做,联合开发准则读者能够认真想一下为什么要这样做。 还有一个典型的用法,咱们定义的实体类的成员变量,总是用private润饰,而后定义get和set办法去操作这些成员变量,那为什么不间接把成员变量定义public,间接操作成员变量呢。 软件设计准则在咱们的开发中处处体现,在一些代码习惯上多思考,做到知其然知其所以然。 二、设计模式分类在设计模式学习过程中能够查阅该文档,学习每个设计模式时,对于他的作用和分类能做到成竹在胸。 1、创立型创立型模式的次要关注点是“怎么创建对象?”,它的次要特点是“将对象的创立与应用拆散”。 单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局拜访点供内部获取该实例,其拓展是无限多例模式。原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型相似的新实例。工厂办法(FactoryMethod)模式:定义一个用于创立产品的接口,由子类决定生产什么产品。形象工厂(AbstractFactory)模式:提供一个创立产品族的接口,其每个子类能够生产一系列相干的产品。建造者(Builder)模式:将一个简单对象分解成多个绝对简略的局部,而后依据不同须要别离创立它们,最初构建成该简单对象。2、结构型结构型模式形容如何将类或对象按某种布局组成更大的构造。它分为类结构型模式和对象结构型模式,前者采纳继承机制来组织接口和类,后者釆用组合或聚合来组合对象。 代理(Proxy)模式:为某对象提供一种代理以管制对该对象的拜访。即客户端通过代理间接地拜访该对象,从而限度、加强或批改该对象的一些个性。适配器(Adapter)模式:将一个类的接口转换成客户心愿的另外一个接口,使得本来因为接口不兼容而不能一起工作的那些类能一起工作。桥接(Bridge)模式:将形象与实现拆散,使它们能够独立变动。它是用组合关系代替继承关系来实现的,从而升高了形象和实现这两个可变维度的耦合度。装璜(Decorator)模式:动静地给对象减少一些职责,即减少其额定的性能。外观(Facade)模式:为多个简单的子系统提供一个统一的接口,使这些子系统更加容易被拜访。享元(Flyweight)模式:使用共享技术来无效地反对大量细粒度对象的复用。组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具备统一的拜访性。3、行为型行为型模式用于形容程序在运行时简单的流程管制,即形容多个类或对象之间怎么相互协作共同完成单个对象都无奈独自实现的工作,它波及算法与对象间职责的调配。 行为型模式分为类行为模式和对象行为模式,前者采纳继承机制来在类间分派行为,后者采纳组合或聚合在对象间调配行为。因为组合关系或聚合关系比继承关系耦合度低,满足“合成复用准则”,所以对象行为模式比类行为模式具备更大的灵活性。 模板办法(Template Method)模式:定义一个操作中的算法骨架,将算法的一些步骤提早到子类中,使得子类在能够不扭转该算法构造的状况下重定义该算法的某些特定步骤。策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们能够互相替换,且算法的扭转不会影响应用算法的客户。命令(Command)模式:将一个申请封装为一个对象,使发出请求的责任和执行申请的责任宰割开。职责链(Chain of Responsibility)模式:把申请从链中的一个对象传到下一个对象,直到申请被响应为止。通过这种形式去除对象之间的耦合。状态(State)模式:容许一个对象在其外部状态产生扭转时扭转其行为能力。观察者(Observer)模式:多个对象间存在一对多关系,当一个对象产生扭转时,把这种扭转告诉给其余多个对象,从而影响其余对象的行为。中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,升高零碎中对象间的耦合度,使原有对象之间不用相互了解。迭代器(Iterator)模式:提供一种办法来程序拜访聚合对象中的一系列数据,而不裸露聚合对象的外部示意。访问者(Visitor)模式:在不扭转汇合元素的前提下,为一个汇合中的每个元素提供多种拜访形式,即每个元素有多个访问者对象拜访。备忘录(Memento)模式:在不毁坏封装性的前提下,获取并保留一个对象的外部状态,以便当前复原它。解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释办法,即解释器。三、UML详解UML类图摘抄自卑话设计模式,我目前见过最好的一张图,便于读者了解。 在面向对象的世界中,蕴含了对象和接口,UML类图次要是能表达出来对象和接口的体现和他们的关系。 对象和接口都是采纳矩形框示意,因为对象蕴含类名、成员变量、成员办法所以用三层来示意,接口没有成员变量,所以采纳两层来示意,为了更易于辨别在接口名上《interface》,另外,抽象类用斜体示意。成员变量均有关键词润饰,+代表public、-代表private、#代表protected 接下来阐明类与类、接口与类之间关系的表白。 继承,空心三角形+实线 实现接口,空心三角形+虚线 关联,实线。企鹅和气象。 聚合,菱形+实现箭头。雁群和大雁。 依赖,虚线箭头。动物依赖水和氧气能力生存。 从本章节开始就正式迈入了面向对象的世界,从增删改查的码农,到真正将编程成为一门艺术。

July 15, 2022 · 1 min · jiezi

关于设计模式:一文搞懂│工厂模式单例模式策略模式适配器模式观察者模式的原理和使用

工厂模式工厂模式的原理作用: 就是你只有传你须要的类进去,你就能失去他的实例化对象其实工厂就是帮你实例化你所须要的类<?php/*** 工厂类*/class factory{ public static function create($className) { return new $className(); }} class A {}class B {} $a = factory::create('A');$b = factory::create('B'); var_dump($a); // object(A)#1 (0) {}var_dump($b); // object(B)#2 (0) {}工厂模式的利用实例化多个类来解决不同业务时候应用,这里以求矩形和圆形的周长和面积为案例<?php/** * Interface shape */interface shape{ public function area(); public function perimeter();} /** * 矩形 * Class rectangle */class rectangle implements shape{ private $width; private $height; public function __construct($width, $height) { $this->width = $width; $this->height = $height; } public function area() { return $this->width * $this->height; } public function perimeter() { return 2 * ($this->width + $this->height); }} /** * 圆 * Class circle */class circle implements shape{ private $radius; public function __construct($radius) { $this->radius = $radius; } public function area() { return M_PI * pow($this->radius, 2); } public function perimeter() { return 2 * M_PI * $this->radius; }} /** * 工厂类 * Class factory */class factory{ public static function create() { switch (func_num_args()) { case 1: return new circle(func_get_arg(0)); break; case 2: return new rectangle(func_get_arg(0), func_get_arg(1)); break; } }} $a = factory::create(4, 5);$b = factory::create(2); echo '矩形的周长为:' . $a->perimeter();echo '矩形的面积为:' . $a->area();echo '圆的周长为:' . $a->perimeter();echo '圆的面积为:' . $a->area(); 单例模式单例模式的原理作用: 当你实例化屡次类的时候,让其只存在在惟一的内存空间中,缩小资源的耗费一般类的实例化,一个 new 将会创立一个实例化内存空间,因为空间不同,这将会导致系统内存开销增大然而同一个类,性能都一样,没必要放在不同的内存空间中<?php/** * Class A */class A {} $a = new A();$b = new A();// 非单例模式中能够看到其中#1,#2分属不同的内存空间var_dump($a); // object(A)#1 (0) {}var_dump($b); // object(A)#2 (0) {}单例模式的定义单例模式的入门口诀是:三私一公公有的构造方法: 避免人为内部应用 new 进行创立这就是下面一般内的实例化了公有的克隆办法: 避免人为内部应用 clone 办法后进行实例化公有的动态属性: 用来存储繁多的实例化对象私有的静态方法: 用来实现繁多的实例化逻辑从后果来看:两个类的对象内存空间都指向了 #1,实现了单例模式的根底构建<?php/** * Class database */class database{ /** * @var $instance */ private static $instance; /** * 公有的构造方法,禁止内部实例化 * database constructor. */ private function __construct() {} /** * 公有的克隆办法,禁止内部克隆 */ private function __clone() {} /** * 获取单例 * @return database */ public static function getInstance() { if(!self::$instance instanceof self) { self::$instance = new self(); } return self::$instance; }} $a = database::getInstance();$b = database::getInstance();var_dump($a); // object(database)#1 (0) {}var_dump($b); // object(database)#1 (0) {}单例模式的利用其实在我的项目中单例模式的利用很多,无非就是有些货色只须要实例化一个对象就行了,不须要屡次进行实例化这其中的利用场景常见的就包含PDO连贯数据库,Redis的连贯等等<?php/** * Class mysql */class mysql{ /** * @var \PDO */ private $pdo; /** * @var $instance */ private static $instance; /** * @var array */ private $_config = [ 'host' => '127.0.0.1', 'post' => 3306, 'user' => 'root', 'password' => '', 'charset' => 'utf8', 'dbname' => 'autofelix', 'except' => 'PDO::ERRMODE_EXCEPTION' ]; /** * mysql constructor. */ private function __construct() {} /** * 数据库链接 */ public function connect() { try { $dsn = "mysql:host={$this->_config['host']};port={$this->_config['post']};dbname={$this->_config['dbname']};charset={$this->_config['charset']}"; $this->pdo = new PDO($dsn, $this->_config['user'], $this->_config['password']); $this->pdo->setAttribute(PDO::ATTR_ERRMODE, $this->_config['except']); } catch (PDOException $e) { exit('数据库连贯失败:' . $e->getMessage()); } } /** * @param $sql * @return array */ public function getAll($sql) { $this->sql = $sql; $pdostatement = $this->pdo->query($sql); return $pdostatement->fetchAll(PDO::FETCH_ASSOC); } /** * @return mysql */ public static function getInstance() { if(!self::$instance instanceof self) { self::$instance = new self(); } return self::$instance; } private function __clone() {}} $mysql = mysql::getInstance();$mysql->connect(); $sql = 'select * from autofelix_users where 1';$result = $mysql->getAll($sql);echo json_encode($result); 策略模式策略模式的原理作用: 比方你去淘宝上买货色,如果你是男生,它的首页会给你举荐男生喜爱的物品,如果你是女生呢,它会给你举荐女生罕用的物品,策略模式其实就是给对象进行分类由下面可知,编程中的策略模式,就是会晓得你是什么人,而后给你举荐你喜爱的货色,让营销最大化这里必然波及到,程序在运行的时候,给你这个人进行分门别类,而后执行了不同的办法导致的这里咱们定义两个类,领有雷同的办法,执行的内容却不同策略模式须要做的就是当用户进来时候,同一个入口让他依据这个人的行为去执行其中某一个类中的办法<?php/** * Class A */class A { public function name() { echo "我是A类"; }} /** * Class B */class B { public function name() { echo "我是B类"; }} /** * Class strategy */class strategy{ /** * @var $obj */ private $obj; /** * @return mixed */ public function getName() { return $this->obj->name(); } /** * @param $class */ public function setClass($class) { $this->obj = $class; }} $strategy = new strategy();// 分门别类// $strategy->setClass(new A());$strategy->setClass(new B());// 同一个入口$strategy->getName(); // 我是B类策略模式的利用情景: 一个用户去某酒店网站定住宿为例,页面上依据你的历史生产记录,会为你显示低等住宿和丰盛的晚餐,或者仅仅显示公众住宿和便宜的自助餐咱们先定义接口去实现住房和晚餐的办法而后定义两个群里的类去实现这个接口,别离是尊贵的人群和一般的人群当有个autofelix用户去订房间,给他注入公众用户的类<?php/** * 定义接口 * Interface userStrategy */interface userStrategy{ public function hotel(); public function dinner();} /** * 尊贵的客人享有的待遇 * Class rich */class rich implements userStrategy{ public function hotel() { return "你是高贵的客人,为你举荐了高级住宿"; } public function dinner() { return "你是高贵的客人,为你举荐了烛光晚餐"; }} /** * 一般的客人享有的待遇 * Class poor */class poor implements userStrategy{ public function hotel() { return "你是一般的客人,为你举荐了公众住宿"; } public function dinner() { return "你是一般的客人,为你举荐了自助餐"; }} /** * Class user */class user{ private $_userClass; public function getHotel() { return $this->_userClass->hotel(); } public function getDinner() { return $this->_userClass->dinner(); } public function setUserClass(userStrategy $userStrategy) { $this->_userClass = $userStrategy; }} /** * 这时候有个autofelix用户过去网站预约房间 * Class autofelix */class autofelix extends user {} $people = new autofelix(); //设置群体$people->setUserClass(new poor()); //获取该群体的住宿和晚餐$hotel = $people->getHotel();$dinner = $people->getDinner(); echo json_encode([ 'hotel' => $hotel, 'dinner' => $dinner]);// 后果如下{ hotel: "你是一般的客人,为你举荐了公众住宿", dinner: "你是一般的客人,为你举荐了自助餐"} 适配器模式适配器模式的原理作用: 将一个类的接口转换成客户心愿的另一个接口,适配器模式使得本来的因为接口不兼容而不能一起工作的那些类能够一起工作比方:在某个场景中,老我的项目写了很多接口公你调用,但忽然有一天,下属说要换个接口办法名调用,须要你用另一个办法名去实现雷同的性能你是间接改后端代码的办法名称?这必定行不通,因为我的项目不止你这一个中央调用这个接口,一旦批改,其余中央就崩了,还是去从新复制那段逻辑代码,改个名字,这样不是不行,只是写了反复代码,显得臃肿了<?php class A{ private $str; public function __construct($str) { $this->str = $str; } public function getStr() { return $this->str; } // 谬误示范,间接复制 getStr 中的代码改个办法名,臃肿 public function getString() { return $this->str; }} //适配器模式前$a = new A('i am autofelix');$result = $a->getStr();var_dump($result);适配器模式的利用而正确的常见,应该是应用适配器模式解决这类问题通过定义对立接口,而后通过实现接口去实现<?php// 我的项目本来代码class A{ private $str; public function __construct($str) { $this->str = $str; } public function getStr() { return $this->str; }}// 定义对立接口interface AInterface { function getString();} class B implements AInterface{ /** * @var A */ private $_A; public function __construct($class) { $this->_A = $class; } public function getString() { return $this->_A->getStr(); }} // 适配器模式前$a = new A('i am autofelix');$result = $a->getStr();var_dump($result);// 适配器模式后$b = new B($a);$result = $b->getString();var_dump($result); 观察者模式观察者模式的原理作用: 用来监控用户的某些操作,而后依据用户这些操作来解决一些后续的事件举个例子:一个用户去网上购买电影票,付款胜利后,零碎须要发短信给用户,顺便记录用户购票的日志等其余多个逻辑操作// 零碎自带的观察者接口// 默认须要实现 onListen 和 getObserverName 这两个办法// 如果是自定义观察者接口名,肯定要实现onListen同性能的办法// onListen 注册监听行为interface InterfaceObserver{ public function onListen($sender, $args); public function getObserverName();}// 定义可被观察者的接口// 其实就是用来监听事件的产生// addObserver 办法咱们是用来依赖注入一些用户购票之后零碎的行为操作// removeObserver 办法,是用来移除某个后续操作的,咱们临时不去实现interface InterfaceObservable{ public function addObserver($observer); public function removeObserver($observer_name);}观察者模式的利用这里以用户购票后须要给用户发送信息和记录购票日志<?php/** * Interface InterfaceObserver * 观察者接口 */interface InterfaceObserver{ public function onListen($sender, $args); public function getObserverName();} /** * Interface InterfaceObservable * 被察看对象接口 */interface InterfaceObservable{ public function addObserver($observer); public function removeObserver($observer_name);} class Ticket implements InterfaceObservable{ /** * @var array */ private $_observers = []; /** * @param $observer */ public function addObserver($observer) { if ($observer instanceof InterfaceObserver) { $this->_observers[] = $observer; } } /** * @param $observer_name */ public function removeObserver($observer_name) {} /** * 用户购票行为 */ public function buy() { //用户购票逻辑,这里不具体阐明,仅仅以参数代之 $result = [ 'code' => 200, 'msg' => '用户购票胜利', 'sign' => 'ea5070bec29826cc0f8e0b7b6861fd75' ]; //购票胜利,开始前期解决 if($result['code'] == 200) { foreach ($this->_observers as $observer) { $observer->onListen($this, $result['sign']); } } }} /** * 记录用户购票日志 * Class TicketRecord */class ticketRecord implements InterfaceObserver{ public function onListen($sender, $args) { echo "记录用户购票胜利,编号为:{$args}<br/>"; } public function getObserverName() {}} /** * 给用户发送观影短信 * Class sendMsg */class sendMsg implements InterfaceObserver{ public function onListen($sender, $args) { echo "您的电影票购买胜利,请凭编号:{$args}观影<br/>"; } public function getObserverName() {}} $ticket = new Ticket();$ticket->addObserver(new ticketRecord());$ticket->addObserver(new sendMsg());$ticket->buy();

July 12, 2022 · 5 min · jiezi

关于设计模式:百度工程师教你玩转设计模式观察者模式

要写好代码,设计模式(Design Pattern)是必不可少的基本功,设计模式是对面向对象设计(Object Oriented Design)中重复呈现的问题的一种无效解决方案,本次从比拟常见的观察者模式动手(Observer Pattern)。在观察者模式中,存在多个观察者对象依赖(Observer)都依赖同一个指标对象(Subject),当被依赖的指标对象发生变化的时候,会告诉所有依赖它的观察者对象,而后各个观察者对象依据本人的须要做出对应的响应。 其次要长处如下: 升高了指标与观察者之间的耦合关系建设了指标与观察者之间的变动触发机制其次要毛病如下: 指标与观察者之间的依赖关系并没有齐全解除,而且有可能呈现循环援用当观察者对象很多时,告诉的发布会破费很多工夫,影响程序的效率比拟形象不好了解?咱们来参考日常功能设计中几个常见的场景。 01观察者模式在天气预报场景的利用关注天气预报是咱们日常生活中一个比拟重要的习惯,不同的角色对于天气的变动由有着不同的反馈。例如今天特大暴雨,气象部门思考的是评估并公布正当的政策领导,教育部门须要评估是否须要复课,应急部门思考的是如何提前准备应急救济,环卫部门须要筹备暴雨后的大量环卫工作,打工人须要思考如何上下班通勤,也存在一些不受此次暴雨影响地区的人什么也不须要思考。联合上述观察者模式的介绍,在此场景中,天气属于被各个角色依赖的指标对象(Subject),气象/教育/应急/环卫等部门,打工人,其余地区的人都属于观察者对象(Observer)。指标对象发生变化后,各个观察者对象收到音讯后都会作出对应的响应措施。基于以上场景实现的简化版观察者模式类图如下: 指标对象(WeatherSubject):即被察看的指标对象,即本例中的天气,持有一个天气状态的属性state,以及绑定观察者的办法attach(),观察者的办法notifyAllObservers()。当状态产生变更后,调用notifyAllObservers()办法告诉所有观察者。形象观察者对象(Observer):用于定义各个观察者的行为规范,也能够采纳接口的形式实现理论观察者对象:MeteorologicalDepartment、RescueDepartment、OfficeWorker、Other等,理论须要关注指标对象并作出响应的角色。继承自形象观察者对象,并基于各自的关注点实现了对于的响应办法update()。基于以上示例的Java版代码demo试下: package com;import java.util.ArrayList;import java.util.List;// 基于天气预报场景的观察者模式实现Demopublic class ObserverPatternDemo { // 天气对象 static class WeatherSubject { private int state; List<Observer> observers = new ArrayList<>(); void attach(Observer observer) { observers.add(observer); } // 告诉观察者 void notifyAllObservers() { for (Observer o : observers ) { o.update(getState()); } } public int getState() { return state; } // 状态变更 public void setState(int state) { this.state = state; if (state == 1) { System.out.println("=====今天要下大暴雨====="); } else { System.out.println("=====今天天气很好呀====="); } // 变更后告诉观察者 notifyAllObservers(); } } // 形象观察者对象 static abstract class Observer { abstract void update(int state); } // 政府气象部门 static class MeteorologicalDepartment extends Observer { @Override void update(int state) { if (state == 1) { System.out.println("【气象部门】收回预警"); } } } // 政府应急救济部门 static class ResumeDepartment extends Observer { @Override void update(int state) { if (state == 1) { System.out.println("【救济部门】筹备应急预案"); } } } // 打工人 static class OfficeWorker extends Observer { @Override void update(int state) { if (state == 1) { System.out.println("【打工人】思考今天怎么上下班通勤"); } else { System.out.println("【打工人】致力搬砖"); } } } // 其余无影响的人 static class Other extends Observer { @Override void update(int state) { if (state == 1) { System.out.println("【其他人】下雨啊,对我影响不大"); } else { System.out.println("【其他人】今天天气不错,进来玩玩"); } } } public static void main(String[] args) { // 初始化指标对象 WeatherSubject subject = new WeatherSubject(); // 初始化观察者对象,并关注指标对象 Observer ob1 = new MeteorologicalDepartment(); Observer ob2 = new ResumeDepartment(); Observer ob3 = new OfficeWorker(); Observer ob4 = new Other(); subject.attach(ob1); subject.attach(ob2); subject.attach(ob3); subject.attach(ob4); // 状态变动: 大暴雨 subject.setState(1); // 状态变动: 好天气 subject.setState(2); //执行后果如下 =====今天要下大暴雨===== 【气象部门】收回预警 【救济部门】筹备应急预案 【打工人】思考今天怎么上下班通勤 【其他人】下雨啊,对我影响不大 =====今天天气很好呀===== 【打工人】致力搬砖 【其他人】今天天气不错,进来玩玩 }}02 观察者模式在领取场景中的利用在领取业务场景下,用户购买一件商品,当领取胜利之后三方会回调本身,在这个时候零碎可能会有很多须要执行的逻辑(如:更新订单状态,发送短信告诉,告诉物流零碎开始备货,赠送礼品…)。 ...

July 8, 2022 · 3 min · jiezi

关于设计模式:php设计模式六观察者模式

观察者模式当一个对象状态产生扭转时,依赖他的对象全副会受到告诉,并自动更新例如:一个事件产生后,要执行一连串的更新操作,传统的为在更新后,写一些业务解决逻辑,代码难以保护,耦合的,新增逻辑须要扭转主体构造观察者模式实现了耦合,非侵入式的告诉和更新机制// 传统形式class Event { public function trigger(){ echo "event"; // 个别是事件产生后,在前面间接写逻辑 }}$e = new Event();//===============================//观察者// 事件产生着abstract class EventGenerator { private $observers = []; // 保留所有观察者 public function addObserver(Observer $observer) // 减少观察者 { $this->observers[] = $observer; } public function notify() // 告诉,事件产生后,告诉观察者执行 { foreach ($this->observers as $observer){ // 一一调用每个观察者的update办法 $observer->update(); } }}// 观察者类interface Observer{ public function update($event_info); // 事件产生后,须要进行的操作}class Event extends EventGenerator { public function trigger(){ // 产生事件后,调用notify,告诉所有观察者触发就能够 $this->notify(); }}$e = new Event();$e->addObserver(new OB1());$e->addObserver(new OB2());$event->trigger();class OB1 implements Observer { public function update (){ echo "ob1"; }}

June 30, 2022 · 1 min · jiezi

关于设计模式:设计模式设计原则

设计准则(SOLID准则)在程序设计畛域, SOLID(繁多性能、开闭准则、里氏替换、接口隔离以及依赖反转)是由罗伯特·C·马丁在21世纪晚期引入,指代了面向对象编程和面向对象设计的五个根本准则。当这些准则被一起利用时,它们使得一个程序员开发一个容易进行软件维护和扩大的零碎变得更加可能。 1. 繁多职责准则(SRP)就一个类而言,应该仅有一个引起它变动的起因。在JavaScript中,须要用到类的场景并不太多,繁多职责准则更多地是被使用在对象或者办法级别上。 如果咱们有两个动机去改写一个办法,那么这个办法就具备两个职责。每个职责都是变动的一个轴线,如果一个办法承当了过多的职责,那么在需要的变迁过程中,须要改写这个办法的可能性就越大。简略说就是:一个对象(办法)只做一件事。 1.1 优缺点长处: 升高了单个类或对象复杂度,依照职责把对象划分为更小粒度,有利于代码复用和单元测试。毛病: 减少编写代码复杂度,对象划分为更小粒度,对象间接的分割也变得更简单。2. 凋谢-关闭准则(OCP)凋谢-关闭准则最早由Eiffel语言的设计者Bertrand Meyer在其著述Object-Oriented Software Construction中提出。它的定义如下: 软件实体(类、模块、函数)等应该对扩大凋谢,然而批改关闭。拓展window.onload函数Function.prototype.after = function(afterfn) { var _self = this; return function() { var ret = _slef.apply(this, arguments); afterfn.apply(this, arguments); return ret; }}window.onload = (window.onload || function() {}).after(function(){ consolo.log("拓展的代码")})通过动静装璜函数的形式,间接拓展了新的函数,而不是间接批改之前的onload相干代码。 3. 里氏替换准则(The Liskov Substitution Principle,LSP)定义如下: 子类的设计要保障在替换父类的时候,不扭转原有程序的逻辑以及不毁坏原有程序的正确性矩形例子: // 思考咱们有一个程序用到上面这样的一个矩形对象:var rectangle = { length: 0, width: 0};// 过后,程序有须要一个正方形,因为正方形就是一个长(length)和宽(width)都一样的非凡矩形,所以咱们感觉创立一个正方形代替矩形。var square = {};(function() { var length = 0, width = 0; Object.defineProperty(square, "length", { get: function() { return length; }, set: function(value) { length = width = value; } }); Object.defineProperty(square, "width", { get: function() { return width; }, set: function(value) { length = width = value; } });})();可怜的是,当咱们应用正方形代替矩形执行代码的时候发现了问题,其中一个计算矩形面积的办法如下:var g = function(rectangle) { rectangle.length = 3; rectangle.width = 4; write(rectangle.length); write(rectangle.width); write(rectangle.length * rectangle.width);};该办法在调用的时候,后果是16,而不是冀望的12,咱们的正方形square对象违反了LSP准则,square的长度和宽度属性暗示着并不是和矩形100%兼容,但咱们并不总是这样明确的暗示。 ...

June 25, 2022 · 2 min · jiezi

关于设计模式:再也不怕面试官追问我设计模式了

平时咱们写代码呢,少数状况都是流水线式写代码,根本就能够实现业务逻辑了。如何在写代码中找到乐趣呢,我感觉,最好的形式就是:应用设计模式优化本人的业务代码。明天跟大家聊聊日常工作中,我都应用过哪些设计模式。 1.策略模式1.1 业务场景假如有这样的业务场景,大数据系统把文件推送过去,依据不同类型采取不同的解析形式。少数的小伙伴就会写出以下的代码: if(type=="A"){ //依照A格局解析}else if(type=="B"){ //按B格局解析}else{ //依照默认格局解析}这个代码可能会存在哪些问题呢? 如果分支变多,这里的代码就会变得臃肿,难以保护,可读性低。如果你须要接入一种新的解析类型,那只能在原有代码上批改。说得业余一点的话,就是以上代码,违反了面向对象编程的开闭准则以及繁多准则。 开闭准则(对于扩大是凋谢的,然而对于批改是关闭的):减少或者删除某个逻辑,都须要批改到原来代码繁多准则(规定一个类应该只有一个发生变化的起因):批改任何类型的分支逻辑代码,都须要改变以后类的代码。如果你的代码就是酱紫:有多个if...else等条件分支,并且每个条件分支,能够封装起来替换的,咱们就能够应用策略模式来优化。 1.2 策略模式定义策略模式定义了算法族,别离封装起来,让它们之间能够互相替换,此模式让算法的变动独立于应用算法的的客户。这个策略模式的定义是不是有点形象呢?那咱们来看点通俗易懂的比喻: 假如你跟不同性情类型的小姐姐约会,要用不同的策略,有的请电影比拟好,有的则去吃小吃成果不错,有的去逛街买买买最合适。当然,目标都是为了失去小姐姐的芳心,请看电影、吃小吃、逛街就是不同的策略。策略模式针对一组算法,将每一个算法封装到具备独特接口的独立的类中,从而使得它们能够互相替换。 1.3 策略模式应用策略模式怎么应用呢?酱紫实现的: 一个接口或者抽象类,外面两个办法(一个办法匹配类型,一个可替换的逻辑实现办法)不同策略的差异化实现(就是说,不同策略的实现类)应用策略模式1.3.1 一个接口,两个办法public interface IFileStrategy { //属于哪种文件解析类型 FileTypeResolveEnum gainFileType(); //封装的专用算法(具体的解析办法) void resolve(Object objectparam);}1.3.2 不同策略的差异化实现A 类型策略具体实现 @Componentpublic class AFileResolve implements IFileStrategy { @Override public FileTypeResolveEnum gainFileType() { return FileTypeResolveEnum.File_A_RESOLVE; } @Override public void resolve(Object objectparam) { logger.info("A 类型解析文件,参数:{}",objectparam); //A类型解析具体逻辑 }}B 类型策略具体实现 @Componentpublic class BFileResolve implements IFileStrategy { @Override public FileTypeResolveEnum gainFileType() { return FileTypeResolveEnum.File_B_RESOLVE; } @Override public void resolve(Object objectparam) { logger.info("B 类型解析文件,参数:{}",objectparam); //B类型解析具体逻辑 }}默认类型策略具体实现 ...

June 23, 2022 · 6 min · jiezi

关于设计模式:代码设计再看设计模式

2 年前作为一个前端菜鸟,首次接触设计模式,立刻上比拟抽象。明天再来更新下我对它的认识。 设计模式也是魔法的一种Dan 说,开发者之间有着一些“共同语言”,来作为传递理念的根底。设计模式就是这些“语言”其中之一。(以下简称设计模式为 DP) DP 基于 OO(源自 Java)的教训稀释的模型,用于开发可保护和扩大的设计。然而其出发点也决定了其起点: 实质是 SOLID 准则中,某项准则的强化,或者几项组合后,失去的代码模式。它比形象略微高一层。基于 OO,回到 OO。脱离 OO 也能利用,然而要真正地了解其原理。有实践认为,DP 是语言缺点的补丁颗粒度较小,只能用于承载纯正的设计。要包容业务(比方浏览器事件模型)则须要回升到框架。40 年中都被奉为软件世界的真谛,撑持起了全世界各个行业大大小小的业务。设计模式相对算得上 CS 中的牛顿定理。咱们学习这些形象,也是设计更大的零碎的基石。比方 Vue、Axios 的源码根本就是 DP 的组合或者变种。没人能仅靠底层语法实现优良设计的。不少自学程序员认为,设计模式属于“花里胡哨的技巧”,因为它不像算法解决理论问题。 ️ 那什么才算理论问题?咱们就要定义一下,什么是“理论问题”了。回忆一下,算法的个性是高效(工夫、空间)解决问题,不然堆一坨 for 实现搜索算法,咱们 Google 一个词条都要花上一天。同样的,暴力堆代码也照样能实现性能,不过维护性就让其他人头痛。会想一下,有多少次咱们被层层重叠的 if..else 绕到头晕目眩。反思一下咱们的工作:80% 的时候,都是在保护,而不是开发新性能。DP 针对维护性和扩展性,恰好就是解决这 80% 场景下的问题。所以,DP 解决的是设计和单干的问题。放弃学习 DP 的人,裸露了两个弱点: 不接触简单设计,满足于低级堆砌代码的业务工作不须要单干,或者单干能力低下,编码只思考本人简单的软件必须有清晰正当的架构,否则无奈开发和保护。如果你的工作中始终用不到 DP 或者其它难度稍高的概念,我感觉应该是时候反思一下,这份工作是否能带来足够的成长。

June 21, 2022 · 1 min · jiezi

关于设计模式:策略模式初探

引入其实介绍设计模式自身并不难,难的在于其该如何在具体的场景中适合的应用,上周在介绍了Shiro之后,我本来打算趁热打铁介绍一下责任链模式,然而责任链模式自身并不简单,咱们接触的也不少,比方拦截器链,过滤器链,每个拦截器和过滤都有机会解决申请。 但在怎么的场景中能够引入责任链模式呢, 我其实也在查对应的材料,在B站上看了不少该模式的视频,然而底下的评论倒不是一边到的齐全叫好,底下的评论倒是说这是适度设计,不如策略模式,所以咱们还是要认分明一件事件,设计模式能够帮忙咱们解决一些问题,就像做饭的酱油,适合的应用可能让咱们的菜变的更美味,然而如果你用不好,酱油放多了或者有些菜不该放酱油,做的菜就会不好吃。这一点咱们能够在Shiro(Java畛域的平安框架)对Java的加密库设计的评估,能够一窥二三。 The JDK/JCE’s Cipher and Message Digest (Hash) classes are abstract classes and quite confusing, requiring you to use obtuse factory methods with type-unsafe string arguments to acquire instances you want to use. JDK的明码和MD5相干的类是十分形象而且让人十分困惑的,要求开发者应用类型不平安的String参数中从简略工厂模式中获取对应的加密实例,这是十分愚昧的。 PS: 我感觉Shiro吐槽的不无道理,上面是JDK中应用MD5算法和Shiro中应用MD5算法的比照,大家能够领会下,兴许就会明确为什么Shiro的设计者吐槽JDK在加密库的设计是愚昧的。 // JDK 中的private static void testMD5JDK() { try { String code = "hello world"; MessageDigest md = MessageDigest.getInstance("MD5"); byte[] targetBytes = md.digest(code.getBytes()); System.out.println(targetBytes); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); }}// 这是Shiro的,我集体感觉Shiro的设计更好private static void testMD5Shiro() { String hex = new Md5Hash("hello world").toHex(); System.out.println(hex.getBytes());}所以我写设计模式的时候基本上会花很大的篇幅介绍这种模式的理念、以及利用场景,我还将UML图逐了进来,我不认为UML图有助于对设计模式的了解,因为看懂UML图自身又须要肯定的学习老本, 一般的图一样能表白设计模式的理念,并且不须要更多的预知概念。 ...

June 19, 2022 · 3 min · jiezi

关于设计模式:百度工程师教你玩转设计模式单例模式

想要写好代码,设计模式(Design Pattern)是必不可少的基本功,设计模式是对面向对象设计(Object Oriented Design)中重复呈现的问题的解决方案,本篇从最简略的单例模式(Singleton Pattern)开讲。 单例模式属于创立型模式(Builder Pattern),用意在于保障一个类仅有一个实例,并提供一个拜访它的全局拜访点。单例模式在内存中仅创立一次对象,即便屡次实例化该类,也只返回第一次实例化后的实例对象,不仅能缩小不必要的内存开销,并且在缩小全局的函数和变量也具备重要的意义。 实现形式上,次要有懒汉式(Lazy Singleton)、饿汉式(Eager Singleton),多线程场景下须要留神线程平安。 场景上,最罕用于全局配置管理,其次在IO操作、前端交互等须要保障对象惟一的场景,也能够应用。 01单例模式的实现形式在golang中单例模式的实现形式有多种,这里介绍下应用init和sync.Once形式实现线程平安的单例。 其中init函数是在文件包首次被加载的时候执行并且只执行一次(Eager Singleton,饿汉模式),sync.Once是在代码运行须要的时候执行且只执行一次(Lazy Singleton,懒汉模式)。init函数形式间接创立好对象,不须要判断对象是否为空并继续占有在内存中,sync.Once是Go语言实现的一种对象,其绝对高效且并发平安的实现原理次要是依赖于sync/atomic包的原子操作,在sync.Once的底层实现中,应用一个变量done来记录函数的执行状态,应用sync.Mutex和sync.atomic来保障线程平安的读取done,以保障某种行为只会被执行一次。须要留神的是once.Do(f func()) 办法不能嵌套,若f在执行过程中也会调用once.Do,会导致死锁。 在golang一些server业务场景利用中,通常会用到一些resource,如罕用的:DB、Redis、Logger等,这些资源的实例化对象会在每个申请中频繁的应用,如果在每个申请的解决过程中频繁创立和开释这些资源对象,则会造成较大的系统资源开销,但如果应用单例的形式创立这些资源对象则能防止这些问题,通常理论应用场景中会在main主过程中的HTTPServer携程启动前,通过init或sync.One的形式创立单例对象提供各HTTPServer携程应用,从而保障各个申请解决过程中应用同一个实例对象。 ......var ( oResource sync.Once initFuncList = []initFunc{ mustInitLoggers, // 初始化Log mustInitServicer, // 初始化servicer以及ral mustInitGorm, // 初始化mysql gorm mustInitRedis, // 初始化redis mustInitOther, // 初始化other })type initFunc func(context.Context) func() error// MustInit 按程序初始化app所需的各种资源func MustInit(ctx context.Context) (f func() error) { oResource.Do(func() { callbackList := make([]func() error, 0, len(initFuncList)) for _, f := range initFuncList { callbackList = append(callbackList, f(ctx)) } f = func() (err error) { for i := len(callbackList) - 1; i >= 0; i-- { if callbackList[i] != nil { e := callbackList[i]() if err == nil { err = e } } } return } }) return}......02单例模式在配置管理中的利用在Python中,一个很广泛的利用场景就是利用单例模式来实现全局的配置管理。对于大部分的零碎,通常都会有一个或者多个配置文件用于寄存零碎运行时所依赖的各种配置信息,在零碎运行的过程中通过代码读取并解析配置文件从而取得对应的配置信息,而且在运行过程中当配置文件产生变更当前还须要实时更新对应的配置信息。 ...

June 10, 2022 · 2 min · jiezi

关于设计模式:模板方法模式初探

好久没写设计模式相干的文章了, 最近看源码的时候碰到一些设计模式,这里就打算将这部分抽出来放在设计模式这个系列中。什么是模板办法模式?为了介绍什么是模板办法模式,咱们再次请出咱们的实习生小陈, 为了不波及公司的外围业务,咱们这里在讲述这个故事的时候,要屏蔽一下外围业务牵扯到具体的场景, 这一天领导给小陈安顿了一个这样的需要, 用代码模仿制作羊肉汤, 目前已知在制作羊肉的时候都会先荡涤,然而烧制办法是不同的,依据教训来说,将来会有更多的羊肉汤来进入到咱们的代码中。 小陈收到了这个需要,心里想既然荡涤的逻辑是独特的的,那这个简略,我就把荡涤抽出来为一个办法,而后再service外面写各自的初加工和烧制办法就能够了。于是写出的代码如下图所示: /** * 这是荡涤办法,所有羊肉都要 荡涤 */public interface MuttonBaseMakeService { void waterMutton();}/** * 再来一个实现类 */@Servicepublic class MuttonBaseMakeServiceImpl implements MuttonBaseMakeService{ @Override public void waterMutton() { System.out.println("先荡涤羊肉"); }}/** * 再来一个牛肉汤service */public interface MuttonSoupService{ /** * 单县羊肉汤 */ void danXianMuttonSoup(); /** * 河南羊肉汤 */ void heNanMuttonSoup();}@Servicepublic class MuttonSoupServiceImpl implements MuttonSoupService{ @Autowired private MuttonBaseMakeService muttonBaseMakeService; @Override public void danXianMuttonSoup() { muttonBaseMakeService.waterMutton(); System.out.println("单县牛肉汤"); } @Override public void heNanMuttonSoup() { muttonBaseMakeService.waterMutton(); System.out.println("河南牛肉汤"); }}感觉实现了工作, 测试也没问题之后,于是找到了领导,领导笑了笑,小陈想了想,上次领导我HttpClient怎么用的时候仿佛也是这个笑容(参见HTTP Client 学习笔记 (一) 初遇篇),心里想这预计是代码写的不行。 ...

June 4, 2022 · 1 min · jiezi

关于设计模式:给前端同学的设计模式精讲课完整无密

download:给前端同学的设计模式精讲课【残缺无密】超极速优化:网络开发中的申请合并!需要如果我有大量的物联网设施,比如说100万台。如果这些设施均匀每10秒产生一个申请,那么QPS就是10W,这对于任何公司来说都是一个不小的规模了。波及到交易等有变更的需要,为了实现幂等操作,通常会提前申请一个交易号(或者说token),来进行惟一的交易申请。这样,实现一个交易,须要至多发动两个申请。一个是申请token,一个是拿着token做交易。尽管说生成token很快,但它是从网络上传输的。且不说当初都是异步模型,就拿网络提早来说,就是一个大的问题。它可能硬生生的把服务质量给降了上来,减少了不确定性,也减少了编码的复杂性。有什么方法来放慢这个过程吗?从HTTP中学习教训大多数人都晓得,TCP有三次握手和四次挥手的机制。这种简短的对话尽管保障了连贯的可靠性,但却损失了不少性能。HTTP从一到三各个版本,都是在尽量减少HTTP连贯的个数,也在缩小交互的次数。在比拟早的HTTP1.0实现中,如果须要从服务端获取大量资源,会开启N条TCP短链接,并行的获取信息。但因为TCP的三次握手和四次挥手机制,在连贯数量减少的时候,整体的代价就变得比拟大在HTTP/1.1中,通过复用长连贯,来改善这个状况,但问题是,因为TCP的音讯确认机制和程序机制以及流量控制策略的起因,资源获取必须要排队应用。一个申请,须要期待另外一个申请传输结束,能力开始HTTP/2采纳多路复用,多个资源能够共用一个连贯。但它解决的只是应用层的复用,在TCP的传输上仍然是阻塞的,前面的资源须要期待后面的传输结束能力持续。这就是队头阻塞景象(Head-of-line blocking)QUIC,也就是HTTP3,形象出了一个stream(流)的概念,多个流,能够复用一条连贯,那么滑动窗口这些概念就不必作用在连贯上了,而是作用在stream上。因为UDP只管发送不论胜利与否的个性,这些数据包的传输就可能并发执行。协定的server端,会解析并缓存这些数据包,进行组装和整顿等。因为形象出了stream的概念,就使得某个数据包传输失败,只会影响单个stream的准确性,而不是整个连贯的准确性。申请黏贴其实,咱们参考TCP的三次握手就能够了。TCP的握手和挥手流程都差不多,但为什么握手是三次,但挥手是四次呢?起因就是TCP把SYN和ACK两个报文,合并成一个返回了。 咱们能够把token看作是序列号,而后把它黏贴在失常的申请里返回就能够了。比方,原来的申请是。一、获取tokenrequest: /getTokenresponse: { "token": "12345"} 复制代码二、提交申请request: /postOrder{ "token": "12345","other": {}} response:{ "status": 200} 复制代码合并后的申请是。request: /postOrder{ "token": "12345","other": {}} response:{ "status": 200,"token": "12346"} 复制代码只须要在每次申请返回的时候,不管胜利还是失败,都附加一个新的token到客户端。客户端缓存这个token,而后发动下个申请。通过这个办法,就能够把两个申请合并为1个申请,实现咱们的优化指标。End在网络编程中,缩小网络交互是一个十分重要的优化,尤其是在弱网环境中。尽管这个技巧很简略,但它很难被想到。优化成果也是微小的,毕竟缩小了一次网络交互。 它有一个嘹亮的名字,那就是三连环。意味着前后申请的连接,永一直环。

May 31, 2022 · 1 min · jiezi

关于设计模式:给前端同学的设计模式精讲课完整无密

download:给前端同学的设计模式精讲课【残缺无密】java中的static关键字说明显还得靠JVM 前言Java中Static想必大家肯定使用过吧。他是用来润饰类或者成员变量或者方法的。对于Static的用法还是很简略的,因为他就是一个修饰词。然而如果不理解他润饰的作用原理的话,可能会闹出bug来变量那么咱们拜访对象中的属性天然也就存放在堆中的。然而当static润饰属性之后他就发生了变动了。 class Demo { //成员变量 public int num = 100; //动态成员变量 public static int count = 200; //动态方法 public static void method(){ System.out.println(count);} }复制代码num属性属于惯例属性,count属性属于动态变量。他们不只仅是名称上的不同。从JVM的角度看他的存放地位也不同。首先num依赖于具体的对象,所以他和对象存放在一起都是堆中。而count独立于对象。JVM中顺便有一块空间用于存放动态变量。这个空间咱们叫做方法区。方法除了润饰变量外,static还可能润饰方法。被润饰的方法咱们叫做动态方法 。动态方法的个性和动态变量一样都属于类而不是对象。动态方法外部只能拜访动态变量而无奈通过this对象进行拜访对象属性。总结下来就是动态方法外部只能拜访动态变量无法访问非动态变量。除了动态方法外,还有一个非凡的方法叫做动态代码块。这个方法不需要咱们筹备方法名,入参,出参等等。只需要筹备方法体。对于方法体外部和动态方法外部申请是一样的。 对于动态代码块和动态方法他们和一般方法还有一个重要的区别就是执行时机。动态变量与一般变量的区别就是内存分布地位,而方法是在栈中操作的,不涉及内存的存储,所以区别就是方法执行的时机。这里需要咱们提前了解点类加载机制。首先咱们一个类的加载分为五个过程。首先是加载class元信息,最初一步是进行初始化。至于后面三步咱们这里可能不理解。重点知道在类加载的最初阶段会进行初始化,而初始化的操作就是执行动态方法和动态代码块。从类加载过程中咱们也能够看的进去动态方法是不依赖于对象的调用的。因为动态方法中只能使用到动态属性。也就是说动态属性使用时还没有创建对象。这也佐证了动态变量不依赖对象的说法。总结本文次要讲解Java基础,请原谅我没有华丽的词藻渲染杰出的文章。诚然基础但经常是咱们容易忽略的学识点。只有不断的学习,才能不断的提高,对于static的进一步使用场景,目前我能想到的就是单例模式中会使用。

May 30, 2022 · 1 min · jiezi

关于设计模式:你说写代码最常用的3个设计模式是啥

作者:小傅哥博客:https://bugstack.cn 积淀、分享、成长,让本人和别人都能有所播种!一、前言:望闻问切 哈喽,大家好,我是技术UP主小傅哥! 哈哈哈,到明天为止,差不多用了3个月里周末和假期的工夫,小傅哥在B站的第一套视频《重学Java设计模式》就全副录制实现了。是的,全网最火的那套设计模式,曾经有视频能够对照着学习了。我曾经录制实现了,那你有跟住学习打卡吗? 录制视频是小傅哥在去年制订的打算,一方面是想锤炼下本人的面对镜头的表达能力,另外也心愿这样的视频能够帮忙更多的初学者更快的上手学习,进步本人的编码能力,也能基于这样的能力去浏览一些框架源码。你可能不晓得,国外很多优良的框架源码 Spring、Mybatis 等,都使用了大量的设计准则和设计模式,只有有设计模式的教训,能力读懂这些源码 另外在视频录制中,小傅哥也学习如何出课件、写资料、录视频、剪辑、配音、配动画,顺便学习应用了一些业余的软件,包含:Neural Mix Pro、Final Cut Pro、剪映、Filmage Screen、OBS、Camo Studio 等。也是有了很大的播种,在当前的视频录制中,也会逐渐更加娴熟,给大家录制出更有技术、更有品质、更易于学习的视频。 其实可能很多人,在没做一件事先,都想着要把所有都筹备好在口头。但其实就像你脑海里过多少遍游泳姿态,只有你不去海边、不上水、不感触,永远也看不到比基尼。所以更无效的方法是要动起来,在口头中补充本人、欠缺物料、继续迭代。 加油,如果你也想做成一件事,当初就口头起来吧! 二、号脉:力不从心鉴于《重学Java设计模式》PDF 的场景实在、内容易学、材料收费,曾经被泛滥号主、UP主,当做了引流工具。以至于很多很多码农,都在本人的收藏夹中都有一本这样的PDF。 当然如果能帮忙到各位同好研发成长,还是十分好的。不过我也晓得其实很多研发搭档并没有关上PDF去学习,因为只有学习就须要在我的代码仓库下载源码,否则只是看书中的插画并不会太大的播种。 其实很多研发搭档也不是不学,说先是材料太多了,看任何一个材料都不深刻,看一会就放弃了。倒置哪一个都没学习明确,但对于xxx学习路线珍藏起来的习惯到一点没变。 不过也不能说大家就不爱学习,有时候只是形式不对。就像小傅哥本人在最开始也并没有先拿着一本设计模式的书籍进行学习,因为很多的设计模式都是实践材料,一些案例也没法用到理论的场景,本人过后对优良源码的积攒也补充。即便有心理写好代码,也力不从心!预计不少的读者在本人的理论开发中也会有这样的感触。 三、诊断:王者光荣你晓得程咬金吗,嗯,就是那个王者光荣里拿着两把西瓜刀贼猛的那个,他是三朝元老,经验了隋朝、唐朝、武周。但就是这么猛的一个人物,在年少学习武术的时候,也只是学会了三十六路宣花斧中的前三招,不过就这三板斧使的炉火纯青。 而程序员学习23种设计模式也一样,没必要在一开始就把所有设计模式都学了,即便学了,你也没有力量都耍进去,就被人家给撂倒了。 那咋办,当然是找3个最罕用的,最能解决本人理论问题的学呀。就这3个练熟了,前面写出的代码也就洁净了,等这3个悟透了,前面的设计模式在学起来、用起来也就没有那么难了。 那这3个设计模式是哪3个呢,小傅哥举荐:模板 + 策略 + 工厂,只有这三个搞定,再搭配着应用,根本就能解决一大票问题,也能让你代码看上去十分有品质。 其实这样的构造分层在 Spring 的源码中也有很多体现,它是一种解耦和职责边界拆散的设计准则,通过这样的实现形式,让代码就是文档的体现。而你理论的编码中,如果有相似这样的流程,也能够定义形象的模板,提供数据撑持的继承和对应策略的配置以及调用解决。当然可能你的逻辑中不须要模板的应用,也能够间接是工厂 + 策略的组合。这样一种简略设计模式的组合,根本是能够解决掉很多研发所遇到的业务场景的,并随着你的场景迭代,在思考这些设计模式的变种,一点点的纯熟才会在短缺的积攒后,写出更加欠缺的合乎本人须要的构造。四、抓药:仙人指路好了,当你曾经看到这里,我猜你未来肯定会成为一个优良的架构师。因为你走在一条小傅哥趟过的路,哈哈哈! 如果你能完完整整的,依照视频,重点、重点,源码!把这两局部联合起来,全副入手写完,那么你肯定会积攒十分多的设计模式实用技巧,也能把这些技巧使用到实在的业务场景中。 视频:https://www.bilibili.com/video/BV1uF411t7pK - B站搜:小傅哥の码场源码:https://github.com/fuzhengwei/CodeDesignTutorials那学完设计模式,接下来呢?接下来就是实战了,在哪里实战?一方面是像小傅哥一样实现《手撸 Spring》、另一方面是参加到有大佬带着你做的简单场景的业务零碎。这两方面都能让你学习的设计模式,失去实际的应用。具体路线参考下图: https://bugstack.cn/ 就是这样一个路线,如果你能残缺的保持走下来,薪资涨幅30%~45%没有问题,曾经测试验证。同时你能够按照这些学习内容,欠缺你的简历:小傅哥写的一份硬核简历!

May 18, 2022 · 1 min · jiezi

关于设计模式:给前端同学的设计模式精讲课完整无密

download:给前端同学的设计模式精讲课【残缺无密】RabbitMq消息丢失原因及其解决打算 一、RabbitMQ消息丢失原因 1.1、消费者丢失消息消费者将数据发送到rabbitmq的时候,可能因为网络问题导致数据就在半路给搞丢了。 1.使用事务(性能差) RabbitMQ 客户端中与事务机制相干的方法有三个: channel.txSelect 、channel.txCommit 和 channel.txRollback。channel.txSelect 用于将以后的信道设置成事务模式,channel.txCommit 用于提交事务,channel.txRollback 用于事务回滚。在通过 channel.txSelect 方法开启事务之后,咱们便可能公布消息给 RabbitMQ 了,如果事务提交胜利,则消息肯定到达了 RabbitMQ 中,如果在事务提交执行之前因为 RabbitMQ异样崩溃或者其余原因抛出异样,这个时候咱们便可能将其捕捉,进而通过执行channel.txRollback 方法来实现事务回滚。注意这里的 RabbitMQ 中的事务机制与大多数数据库中的事务概念并不相同,需要注意分别。 事务确实能够解决消息发送方和 RabbitMQ 之间消息确认的问题,只有消息胜利被RabbitMQ 接收,事务才能提交胜利,否则便可在捕捉异样之后进行事务回滚,与此同时可能进行消息重发。然而使用事务机制会“吸干”RabbitMQ 的性能。 2.发送回执确认(推荐) 消费者将信道设置成 confirm(确认)模式,一旦信道进入 confirm 模式,所有在该信道下面公布的消息都会被指派一个唯一的 ID(从 1 开始),一旦消息被投递到所有匹配的队列之后,RabbitMQ 就会发送一个确认(Basic.Ack)给消费者(蕴含消息的唯一 ID),这就使得消费者通晓消息已经正确到达了目的地了。如果消息和队列是可持久化的,那么确认消息会在消息写入磁盘之后收回。RabbitMQ 回传给消费者的确认消息中的 deliveryTag 蕴含了确认消息的序号,此外 RabbitMQ 也可能设置 channel.basicAck 方法中的 multiple 参数,示意到这个序号之前的所有消息都已经失去了处理,注意辨别这里的确认和生产时候的确认之间的异同。 注意要点: 事务机制和 publisher confirm 机制两者是互斥的,不能共存。 事务机制和 publisher confirm 机制确保的是消息能够正确地发送至 RabbitMQ,这里的“发送至 RabbitMQ”的含意是指消息被正确地发往至 RabbitMQ 的交换器,假如此交换器没有匹配的队列,那么消息也会丢失。 1.2、RabbitMQ弄丢了数据-开启RabbitMQ的数据持久化 为了防止rabbitmq自己弄丢了数据,这个你必须开启rabbitmq的持久化,就是消息写入之后会持久化到磁盘,哪怕是rabbitmq自己挂了,复原之后会主动读取之前存储的数据,一般数据不会丢。除非极其罕见的是,rabbitmq还没持久化,自己就挂了,可能导致大量数据会丢失的,然而这个概率较小。 设置持久化有两个步骤,第一个是创建queue的时候将其设置为持久化的,这样就可能保障rabbitmq持久化queue的元数据,然而不会持久化queue里的数据;第二个是发送消息的时候将消息的deliveryMode设置为2,就是将消息设置为持久化的,此时rabbitmq就会将消息持久化到磁盘下来。必须要同时设置这两个持久化才行,rabbitmq哪怕是挂了,再次重启,也会从磁盘上重启复原queue,复原这个queue里的数据。 而且持久化可能跟消费者那边的confirm机制配合起来,只有消息被持久化到磁盘之后,才会告诉消费者ack了,所以哪怕是在持久化到磁盘之前,rabbitmq挂了,数据丢了,消费者收不到ack,你也是可能自己重发的。 ...

May 12, 2022 · 1 min · jiezi

关于设计模式:给前端同学的设计模式精讲课吾爱fen享

download:https://www.sisuoit.com/2900.... 需要对于须要前端实现无痛刷新Token,无非就两种: 申请前判断Token是否过期,过期则刷新申请后依据返回状态判断是否过期,过期则刷新 解决逻辑实现起来也没多大差异,只是判断的地位不一样,外围原理都一样: 判断Token是否过期没过期则失常解决过期则发动刷新Token的申请拿到新的Token保留从新发送Token过期这段时间内发动的申请重点: 放弃Token过期这段时间发动申请状态(不能进入失败回调)把刷新Token后从新发送申请的响应数据返回到对应的调用者 实现 创立一个flag isRefreshing 来判断是否刷新中创立一个数组队列retryRequests来保留须要从新发动的申请判断到Token过期 isRefreshing = false 的状况下 发动刷新Token的申请 刷新Token后遍历执行队列retryRequests isRefreshing = true 示意正在刷新Token,返回一个Pending状态的Promise,并把申请信息保留到队列retryRequests中 import axios from "axios";import Store from "@/store";import Router from "@/router";import { Message } from "element-ui";import UserUtil from "@/utils/user"; // 创立实例const Instance = axios.create();Instance.defaults.baseURL = "/api";Instance.defaults.headers.post["Content-Type"] = "application/json";Instance.defaults.headers.post["Accept"] = "application/json"; // 定义一个flag 判断是否刷新Token中let isRefreshing = false;// 保留须要从新发动申请的队列let retryRequests = [];

May 12, 2022 · 1 min · jiezi

关于设计模式:线程安全的几种单例模式

单例模式单例模式是 Java 中罕用的设计模式之一,属于设计模式三大类中的创立型模式。在运行期间,保障某个类仅有一个实例,并提供一个拜访它的全局拜访点。单例模式所属类的构造方法是公有的,所以单例类是不能被继承的。实现线程平安的单例模式有以下几种形式:1.饿汉式 public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }这是实现一个平安的单例模式的最简略粗犷的写法,之所以称之为饿汉式,是因为肚子饿了,想马上吃到货色,不想期待生产工夫。在类被加载的时候就把Singleton实例给创立进去供应用,当前不再扭转。 长处:实现简略, 线程平安,调用效率高(无锁,且对象在类加载时就已创立,可间接应用)。 毛病:可能在还不须要此实例的时候就曾经把实例创立进去了,不能延时加载(在须要的时候才创建对象)。 2.懒汉式 public class Singleton { private static Singleton instance = null; private Singleton() { } //如果没有synchronized,则线程不平安 public static synchronized Singleton getInstance() {//synchronized也能够写在办法里,造成同步代码块 if (instance == null) { instance = new Singleton(); } return instance; } }相比饿汉式,懒汉式显得没那么“饿”,在真正须要的时候再去创立实例。 长处:线程平安,能够延时加载。 毛病:调用效率不高(有锁,且须要先创建对象)。 3.懒汉式改良版(双重同步锁) ...

May 6, 2022 · 2 min · jiezi

关于设计模式:设计模式专题之Proxy静态代理与动态代理

简介 用意: 为其余对象提供一种代理以管制整个对象的拜访。 次要解决: 在间接拜访对象时带来的问题,比如说:要拜访的对象在近程的机器上。在面向对象的零碎中,有些对象因为某些起因(比方对象创立开销很大,或者某些操作须要安全控制,或者须要过程外的拜访),间接拜访会给使用者或者系统结构带来很多麻烦,咱们能够在拜访此对象时加上一个对此对象的拜访层。 长处: 职责清晰高扩展性智能化毛病: 因为在客户端和实在主题之间减少了代理对象,因而有些类型的代理模式可能会造成申请的处理速度变慢。实现代理须要额定的工作,有些代理模式实现起来非常复杂。应用场景: 近程代理虚构代理Copy-on-Write代理爱护代理Cache代理防火墙代理同步化代理智能援用代理实现动态代理动态代理在应用时,须要定义接口或者父类,被代理对象与代理对象一起实现雷同的接口或者是继承雷同父类。 接口 interface Movable { void move();}被代理类,实现该接口move办法 public class Tank implements Movable { /** * 模仿坦克挪动了一段儿工夫 */ @Override public void move() { System.out.println("Tank moving claclacla..."); try { Thread.sleep(new Random().nextInt(10000)); } catch (InterruptedException e) { e.printStackTrace(); } }}代理类同样实现该接口,增加Movable属性,实现move办法外部调用传入的被代理类的move办法,在调用前后能够增加一些业务代码 class TankTimeProxy implements Movable { Movable m; public TankTimeProxy(Movable m) { this.m = m; } @Override public void move() { long start = System.currentTimeMillis(); m.move(); long end = System.currentTimeMillis(); System.out.println(end - start); }}最初应用main办法调用代理类的move办法,如果须要多个代理类,能够多层嵌套应用 ...

May 5, 2022 · 3 min · jiezi

关于设计模式:设计模式之工厂模式深入解析简单工厂模式工厂方法模式和抽象工厂模式

工厂模式创立型模式: 对类的实例化过程进行形象,可能将对象的创立和对象的应用拆散开来 为了使得软件的构造更加清晰,外界对于这些对象应用只须要晓得独特的接口,而不在意具体实现的细节,这样使得整个零碎更加合乎繁多职责的准则创立型模式暗藏了类的实例的创立细节,通过暗藏对象创立和组合过程从而使得整个零碎互相独立的目标创立型模式在创立什么,由谁创立,何时创立更加灵便工厂模式是一个重要的创立型模式,次要性能就是实例化对象工厂模式: 负责将有独特接口的类实例化 次要解决接口抉择问题在不同的条件下须要创立不同的实例时应用工厂模式是一种创立型模式,提供了创建对象的最佳形式应用工厂模式创建对象不会对客户端裸露创立逻辑,并且应用一个独特的接口来指向新创建的对象工厂模式在子类中实现工厂接口,创立过程在子类中执行工厂模式的分类: 简略工厂模式Simple Factory工厂办法模式Factory Method形象工厂模式Abstract Factory工厂模式长处: 能够使得代码构造清晰,无效地封装变动对调用者屏蔽具体的产品类升高代码的耦合度工厂模式的应用场景: 在任何须要生成简单对象的中央,都能够应用工厂办法模式.只有简单的对象才实用于工厂办法模式.对于简略的只有通过new就能够实现创立的对象,无需应用工厂模式.如果简略对象应用工厂模式,须要引入一个工厂类,减少零碎的复杂度工厂模式是一种典型的解耦模式,当类之间须要减少依赖关系时,能够应用工厂模式升高零碎之间的耦合度工厂模式是依附形象架构的,将实例化的工作交给子类实现,扩展性好.当零碎须要较好的扩展性时,能够应用工厂模式,不同的产品应用不同的工厂来实现组装简略工厂模式简略工厂模式Simple Factory Pattern: 定义一个类用于负责创立其余类的实例,依据自变量的不同返回不同类的实例,被创立的实例通常都有一个独特的父类简略工厂模式中用于创立实例的办法时动态static办法,因而又称作是动态工厂办法模式简略工厂模式的角色: 工厂类Factory : 简略工厂模式外围类. 负责创立所有产品的外部逻辑,工厂类能够被内部调用,创立所需对象形象产品类Product : 工厂类创立的所有对象的父类,封装产品的共有办法.进步零碎的灵活性.使得工厂类只须要定义一个通用的工厂办法,因为所有创立的具体产品都是这个子类对象具体产品类ConcorrectProduct: 所有被创立的对象都是这个类的具体实例,须要实现形象产品中申明的形象办法简略工厂模式代码实现简略工厂模式长处: 简略工厂模式提供了专门的类用于创建对象,实现了对责任的宰割. 工厂类Factory中含有必要的判断逻辑,决定创立具体产品类ConcreteProduct的实例,客户端只须要生产产品客户端不须要晓得须要创立的具体产品类ConcreteProduct的类名,只须要晓得具体产品类ConcreteProduct对应的参数即可通过引入配置文件,能够在不批改客户端的状况下批改和减少新的产品类ConcreteProduct, 进步了零碎的灵活性简略工厂模式毛病: 工厂类Factory集中了所有产品的创立逻辑,如果产生异样,整个零碎都会产生故障简略工厂模式中减少了零碎中类的个数,减少了零碎的复杂度和了解难度简略工厂模式中如果须要增加新的产品须要批改工厂逻辑,违反了开闭准则,不利于零碎的扩大和保护简略工厂模式应用了静态方法,无奈造成基于继承的等级构造简略工厂模式的应用场景: 工厂类中负责创立的对象比拟少时客户端只须要晓得传入工厂类的参数,不关怀创建对象的参数简略工厂类的实现形式间接传入判断参数keyFactory: public class Factory { public static Product produce(String concreteProductType) { switch (concreteProductType) { case "A" : return new ConcreteProductA(); break; case "B" : return new ConcreteProductB(); break; default : throw new Exception("没有对应的产品类型"); break; } }}问题: 如果新增产品类,须要在工厂类中新增case违反了开闭准则,这种办法是不倡议应用的利用反射Factory:public Class Factory { public static Product produce(String concreteProductClassPathName) throw Exception { try { Product product = (Product)Class.forName(concreteProductClassPathName).newInstance(); return product; } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } throw new Exception("没有对应的产品"); }}问题: ...

March 17, 2022 · 2 min · jiezi

关于设计模式:面试常问的设计模式之代理模式的详细解析分析说明静态代理模式和动态代理模式

Proxy-代理模式代理模式代理模式: Proxy Pattern. 指为对象提供一种代理,用以管制对这个对象的拜访. 是一种结构型模式代理模式蕴含三种角色: 形象角色Subject: 申明实在角色和代理角色独特接口办法.该类能够是接口也能够是抽象类代理角色ProxySubject: 代理类. 代理对象外部蕴含对实在对象的援用,同时代理对象提供与实在对象雷同的接口,能够代替实在对象. 同时,代理对象能够在执行实在对象操作时,附加其余的操作,相当于对实在对象进行封装实在角色RealSubject: 被代理类. 进行代理的实在对象,负责执行零碎的真正的逻辑业务对象.调用实在对象办法,都要通过代理角色进行代理个别代理能够了解为代码加强,实际上就是在原代码逻辑前后减少一些解决逻辑,而调用者无感知.代理模式属于结构型模式,分为动态代理和动静代理代理模式通用写法动态代理动态代理: 须要定义接口或者父类,被代理的对象和代理对象须要实现雷同的接口或者雷同的父类长处: 能够做到在不批改指标对象的性能前提下,对指标性能进行扩大毛病: 因为代理对象须要与实在对象实现同样的接口,所以会有很多代理类如果接口减少办法,实在对象与代理对象都要进行保护动态代理示例动静代理动静代理特点: 代理对象不须要实现接口动静代理是利用JDK的API, 动静地在内存中构建代理对象.须要指定创立的代理对象或者指标对象实现的接口类型Java动静代理Java中JDK动静代理API所在的包 : java.lang.reflect.ProxyJDK实现动静代理只须要应用newProxyInstance() 办法: /** * 获取指定接口的代理类实例,该代理类将办法调用调配给指定的调用处理程序 * 该办法相当于: * Proxy.getProxyClass(loader, interfaces) * .getConstructor(new Class[] { InvocationHandler.class }) * .newInstance(new Object[] { handler }) * .getConstructor(new Object[] { InvocationHandler.class }); * * @param loader 指定以后实在对象应用的类加载器,获取加载器的办法是固定的 * @param interfaces 实在对象实现的接口类型,应用泛型的形式确认类型 * @param h 事件处理,执行实在对象的办法时,会触发事件处理器的办法,会将以后执行指标对象的办法作为参数传入 */public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);动静代理示例Java动静代理要求被代理的对象必须是一个实现了接口的对象: 起因在于Java动静代理生成代理类时默认继承的Proxy依据Java的单继承多实现的个性,只能实现对接口对象的代理CGLIB代理动态代理模式和动静代理模式要求指标对象是一个实现了接口的对象 ...

March 16, 2022 · 1 min · jiezi

关于设计模式:观察者模式与发布订阅模式区别-JS

观察者模式当对象之间存在一对多的依赖关系时,当被察看的对象状态产生扭转时,所有察看它的对象都会收到告诉,这就是观察者模式。 根本思维在观察者模式中,只有两种主体:指标对象 (Subject) 和 观察者 (Observer)。在观察者模式中,Subject 对象领有增加、删除和告诉一系列 Observer 的办法等,而 Observer 对象领有 update 更新办法等。在 Subject 对象增加了一系列 Observer 对象之后,Subject 对象则维持着这一系列 Observer 对象,当无关状态产生变更时 Subject 对象则会告诉这一系列 Observer 对象进行更新。 长处耦合度高,通常用来实现一些响应式的成果;角色很明确,没有事件调度核心作为两头者,指标对象Subject和观察者Observer都要实现约定的成员办法;单方分割严密,指标对象的主动性很强,本人收集和保护观察者,并在状态变动时被动告诉观察者更新;实现// 指标对象class Subject { constructor() { this.observers = [] } add (observer) { this.observers.push(observer) } notify() { this.observers.map(observer => { if (observer && typeof observer.update === 'function') { observer.update() } }) } remove(observer) { const idx = this.observers.findIndex(itm => itm === observer) if (idx !== -1) { this.observers.splice(idx, 1) } }}// 观察者class Observer { constructor(name) { this.name = name } update() { console.log(`${this.name} updated`) }}const subject = new Subject()const o1 = new Observer('Nina')const o2 = new Observer('Jack')subject.add(o1)subject.add(o2)console.log('第一次告诉:')subject.notify()subject.remove(o1)console.log('删除 Nina 后,再次告诉:')subject.notify()输入为: ...

March 14, 2022 · 1 min · jiezi

关于设计模式:重学Java设计模式作者开始录视频了

作者:小傅哥博客:https://bugstack.cn 积淀、分享、成长,让本人和别人都能有所播种!1. 前言哈哈哈,终于对B站下手了! 大家好,我是小傅哥,在缓和、羞涩到适应后,哈哈哈,终于开始承受视频里传出本人的西南茬子声音。所以我决定开始在B站搞事(内卷启动):全面铺设技术学习视频,让干货内容往前挤一挤! 相熟小傅哥的都晓得,小傅哥有一个博客:bugstack.cn 硬核到能够把你的薪资待遇拉倒P6~P7,内容涵盖:面经手册、Netty4.x,手写Spring,用Java实现JVM,重学Java设计模式,SpringBoot中间件开发,IDEA插件开发,DDD零碎架构我的项目开发,字节码编程...等泛滥辅助读者通往架构师路上的核心技术。连忙看看博客吧,错过就是错过钱 但这些内容在学习上对于初学者的小白或者卡在瓶颈期大白(●—●)来说的确有些艰难,甚至有点劝退,不是不想学只是学不会。所以作为技术分享者的小傅哥,决定开始铺博客所写内容的技术视频,一方面满足于小傅哥的粉丝搭档更加容易的学习,另一方面也让我习惯和承受本人茬子视频口音的感觉。 名称:小傅哥の码场 - 扫码关注,白皮袄技术地址:https://space.bilibili.com/15637440 - 本篇文章点击浏览原文,也能够间接进入小傅哥的B站视频地址 - 关注我、关注我、关注我2. B站视频《重学Java设计模式》《重学Java设计模式》 是一本互联网实在案例实际书籍。以落地解决方案为外围,从理论业务中抽离出,交易、营销、秒杀、中间件、源码等22个实在场景,来学习设计模式的使用。 如果你还没有这本书籍也能够通过关注公众号:bugstack虫洞栈 回复:1024 进行下载 - 当然你也能够在JD、当当、拼多多上购买纸质书籍反对小傅哥 已录制完了7个视频,看视频学起来更难受: 在B站成体系的设计模式视频录制,通过理论生存中的案例(拆自行车、传女不传男、皇帝传圣旨...)隐射开发思维,让读者能够更加容易的了解和记住这样的设计模式思维。每一个视频章节都会有与之匹配的理论编程案例(回绝三角形、长方形、圆形的假案例),以及在我的项目中是如何实际应用和体现的,这样也能让读者真正的感触到设计模式到底能帮忙你干啥。3. 学习打卡,内卷启动如果你感觉本人学习有些吃力、保持3天热度就开始气馁、没有圈子短少氛围。那么十分倡议你退出小傅哥的 付费 常识圈子,你能够了解为是退出了付费的微信群和高级研发朋友圈。(常识星球 == 微信、小傅哥的常识星球 == 小傅哥创立的高级研发学习朋友圈) 在星球中,小傅哥会给退出的读者提供 1对1 问题解答、组织学习打卡、安顿我的项目实际、定期简历批阅、录制教程视频、分享电子书材料等。从而提效大家的学习货色、播种常识、意识搭档&播种友情(大厂架构师、高级码农、海内(哥伦布/华盛顿)研发、211&985研究生) - 花点钱,一份小小的投资,退出高质量的学习交换圈子和技术群 常识星球反对 APP、网页和小程序(公众号:bugstack虫洞栈 间接进入),不便随时随地的应用,每天刷一刷;总结、记录、分享,一年后播种满满(薪资拉高一个段位)! 3.1 学习气氛 3.2 退出星球 - 一次靠近大佬排汇教训的机会退出:https://t.zsxq.com/jAi2nUf 星主:小傅哥,《重学Java设计模式》作者,一线大厂架构师,长年的技术分享、架构设计、中间件开发,有着十分丰盛的简单我的项目架构设计能力和工程落地教训,能够携你一起成长提高。退出星球,你将取得: 学习 Lottery 分布式抽奖秒杀我的项目 - 基于畛域驱动设计的落地实际【面大厂利器】- 一个我的项目,带你拿个高薪Offer!提供博客 https://bugstack.cn 所有学习内容的领导、帮忙GitHub:https://github.com/fuzhengwei/CodeGuide - 十分有价值的技术材料仓库,包含小傅哥所有的博客凋谢案例代码能够在发送你的简历到我的邮箱(见应用介绍),提供简历批阅服务提供技术问题、零碎架构、学习成长、降职问难等各项内容的答复定期的整顿和分享出各类专属星球的技术小册、编程视频、PDF文件定期组织技术直播分享,传道、受业、解惑,晓得阶段瓶颈冲破技巧4. 学完设计模式,会用了!尽管很多研发都理解过设计模式,但大多数都只是理解设计模式的实践,十分的短少设计模式的我的项目实际,也就压根了解不到设计模式能给本人的我的项目带来什么样的益处。所以,很多时候都说设计模式简单没必要用 其实小声说就是本人不会用,短少教训,不敢用,用不好! 如果你是这样的研发,可能真的写不了多久代码就要想着走治理路线了,毕竟你的代码程度和刚来的应届生也没多少区别,甚至人家年轻人上来卷你一周,你就趴下了。 如果你是这样的状况,那么就退出小傅哥这趟车一起学习吧,至多你能在这趟车学会几个十分罕用的设计模式写法,这也是为你的技术职业生涯续命。况且还是重学Java设计模式的作者带着你一起卷呢! 4.1 没吃下蛋公鸡前 不应用设计模式的代码,总是一片一片的凌乱不堪,白天写bug,早晚出事变!4.2 吃了下蛋公鸡后 会应用设计模式的代码洁净、整洁清晰的划分类的职责边界和界线上下文,就这样的代码在做代码评审的时候,必定给你夸红了脸,加足了钱。这个十分洁净的能让你学习到货色还能加薪的代码,就是退出星球后的 Lottery 抽奖零碎 - 基于畛域驱动设计的四层架构实际 - 也是设计模式的实际我的项目,学习下相对能够把握相对局部罕用的设计模式!好嘞,再次感激读者粉丝的反对,我会尽本人最大的致力"卷死各位"继续欠缺和经营星球,让每一个退出的读者都有十分大的播种! ...

March 14, 2022 · 1 min · jiezi

关于设计模式:设计模式二三事

设计模式是泛滥软件开发人员通过长时间的试错和利用总结进去的,解决特定问题的一系列计划。现行的局部教材在介绍设计模式时,有些会因为案例脱离实际利用场景而令人费解,有些又会因为场景简略而显得有些小题大做。本文会联合在美团金融服务平台设计开发时的教训,结合实际的案例,并采纳“师生对话”这种绝对滑稽的模式去解说三类罕用设计模式的利用。心愿能对想晋升零碎设计能力的同学有所帮忙或启发。引言话说这是在程序员世界里一对师徒的对话: “老师,我最近在写代码时总感觉本人的代码很不优雅,有什么方法能优化吗?” “嗯,能够思考通过教材零碎学习,从正文、命名、办法和异样等多方面实现整洁代码。” “然而,我想说的是,我的代码是合乎各种编码标准的,然而从实现上却总是感觉不够简洁,而且总是须要重复批改!”学生小明叹气道。 老师看了看小明的代码说:“我明确了,这是零碎设计上的缺点。总结就是形象不够、可读性低、不够强壮。” “对对对,那怎么能迅速进步代码的可读性、健壮性、扩展性呢?”小明急不可耐地问道。 老师敲了敲小明的头:“不要太塌实,没有什么办法能让你立即成为零碎设计专家。然而对于你的问题,我想设计模式能够帮到你。” “设计模式?”小明不解。 “是的。”老师点了拍板,“世上本没有路,走的人多了,便变成了路。在程序员的世界中,本没有设计模式,写代码是人多了,他们便总结出了一套能进步开发和保护效率的套路,这就是设计模式。设计模式不是什么教条或者范式,它能够说是一种在特定场景下普适且可复用的解决方案,是一种能够用于进步代码可读性、可扩展性、可维护性和可测性的最佳实际。” “哦哦,我懂了,那我应该如何去学习呢?” “不急,接下来我来带你缓缓理解设计模式。” 处分的发放策略第一天,老师问小明:“你晓得流动营销吗?” “这我晓得,流动营销是指企业通过参加社会关注度高的已有流动,或整合无效的资源自主策动大型流动,从而迅速进步企业及其品牌的知名度、美誉度和影响力,常见的比方有抽奖、红包等。” 老师点点头:“是的。咱们假如当初就要做一个营销,须要用户参加一个流动,而后实现一系列的工作,最初能够失去一些处分作为回报。流动的处分蕴含美团外卖、酒旅和美食等多种品类券,当初须要你帮忙设计一套处分发放计划。” 因为之前有过相似的开发教训,拿到需要的小明二话不说开始了编写起了代码: // 处分服务class RewardService { // 内部服务 private WaimaiService waimaiService; private HotelService hotelService; private FoodService foodService; // 应用对入参的条件判断进行发奖 public void issueReward(String rewardType, Object ... params) { if ("Waimai".equals(rewardType)) { WaimaiRequest request = new WaimaiRequest(); // 构建入参 request.setWaimaiReq(params); waimaiService.issueWaimai(request); } else if ("Hotel".equals(rewardType)) { HotelRequest request = new HotelRequest(); request.addHotelReq(params); hotelService.sendPrize(request); } else if ("Food".equals(rewardType)) { FoodRequest request = new FoodRequest(params); foodService.getCoupon(request); } else { throw new IllegalArgumentException("rewardType error!"); } }}小明很快写好了Demo,而后发给老师看。 ...

March 14, 2022 · 7 min · jiezi

关于设计模式:重新学习设计模式一什么是设计模式

始终以来,设计模式是一个令人头疼的课题,记得之前在A公司做智能客服我的项目时,刚开始只是一个小我的项目,不论什么设计模式,零碎架构,全程间接上手敲业务代码,两三天工夫就把所有的代码敲完上线应用,后果谁也没想到忽然我的项目大起来了,十几个业务部门的业务一拥而上,开始招人,上手业务,后果。。。大家都是苦力干嘛,拼命加班,拼命填坑,十几个人的代码乌七八糟,大量反复业务,反复代码,单简略的一样表单业务查问就有三四不同的版本,新来的员工也在埋怨没学到任何技术,倒学会怎么跟业务吵架,那日子切实是不忍直视。。。 设计模式是什么?这个是陈词滥调的问题了,它并不是教人如何设计用户界面,怎么学习编程语言,也不是通知你什么是面向对象数据库等办法。设计模式是一套能够被重复应用、少数人通晓的、通过分类编目标、代码设计教训的总结。在软件设计过程中能够设计成解决一些一直反复的业务,以及该问题的解决方案。也就是说,它是解决特定问题的一系列套路(比方太极拳套路等),是前辈们的代码设计教训的总结,具备肯定的普遍性,能够重复应用。这样做的目标是为了进步代码的可重用性、代码的可读性,程序的可维护性和代码的可靠性。 通过学习了解设计模式有以下三个播种: 进步编程思维:能够进步咱们的编程思维能力、编程理解能力和设计程序的能力。程序设计标准化:能够让咱们的程序设计更加标准化、代码编写工程化、进步开发效率、从而缩短软件的开发周期代码易于了解:好的设计模式能够使代码设计的可重用性高、可读性强、可靠性高。代码构造更灵便、易于保护。 总的来说,设计模式只是一个疏导。在理论的软件开发中,咱们必须依据零碎架构的应用程序特点失当抉择适合的设计模式。对于简略的程序,简略的业务场景,只须要一个简略的数据结构就能够解决的业务,没必要在下面花太多工夫,简略的事件简略解决。但对于大型项目的开发或框架设计,用设计模式来设计代码,那必定是上上策,必须抉择设计模式。 对于每个规范来说,都有本人的基本要素,咱们要理解明确设计模式的基本要素,这样咱们就能够跟设计者有共同语言交换,设计模式通常有几个基本要素,比方:模式名称、别名、动机、问题、解决方案、成果、构造、模式角色、单干关系、实现办法、适用性、已知利用、例程、模式扩大和相干模式等,其中驰名的GoF列举其中的四大因素: 模式名称:这只是一个代记词,就跟咱们的人名一样,便于记忆,一个好的名称能够通过名称理解模式的问题、解决方案和成果,也能够帮忙咱们思考,便于咱们与其他人交换设计思路及设计后果,取一个失当的模式名就跟咱们平时写代码取一个好的办法及类一样,不是那么容易问题(or 应用场景):问题是形容咱们在何时什么场景应用这个模式,它必须解释了设计问题(场景)或问题(场景)存在的前因后果,也可能形容了特定场景的设计思路、一种设计必须基于一个或多个问题 or 场景而设计的,这部分是设计模式中不可或缺的条件解决方案:有了问题,就要有解决方案,咱们理解到的模式就相似一个模板,解决某个问题或场景的模板,那么模板就有具体的设计或实现形式。解决方案就是针对这个问题 or 场景的一种设计组成部分,能够用于多种场合,它的思路并不只针对于特定的问题而设计或实现的,能够应用同类或类似的问题场景,而是提供设计问题的形象形容和怎么用一个具备个别语义的元素组合(java语言中的类或对象组合)来解决这个问题。成果:有了问题,有解决方案,当然要有解决方案的成果,总不能说我这个解决方案很厉害,但对于这个问题,成果不好,这不是扯淡吗?成果个别都是从两个方面来形容:长处、毛病。模式成果形容了模式利用的成果及应用模式应衡量的问题,对于评估一个设计抉择和了解应用模式的代价及益处是十分有意义的,软件的大多数比拟关注对工夫和空间的掂量,也是表白了语言和实现问题成果。这对系统的灵活性、扩充性或可移植性有肯定的影响。 以上是我集体对于重温设计模式的认识,当然每个人思考问题的形式不一样,出发点不同,会产生对于设计模式的了解不一样,一个人设计进去的程序对于另一个人来说只是基本思路,根本结构局部而已,有工夫大家能够一起交换探讨。

March 6, 2022 · 1 min · jiezi

关于设计模式:JAVA-23种设计模式详解

单例设计模式这种类型的设计模式属于创立型模式,它提供了一种创建对象的最佳形式。这种模式波及到一个繁多的类,该类负责创立本人的对象,同时确保只有单个对象被创立。这个类提供了一种拜访其惟一的对象的形式,能够间接拜访,不须要实例化该类的对象。 工厂模式简略工厂模式封装了创建对象的过程,能够通过参数间接获取对象。把对象的创立和业务逻辑层离开,这样当前就防止了批改客户代码,如果要实现新产品间接批改工厂类,而不须要在原代码中批改,这样就升高了客户代码批改的可能性,更加容易扩大。 工厂办法模式定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂办法使一个产品类的实例化提早到其工厂的子类。 形象工厂模式是一种为拜访类提供一个创立一组相干或相互依赖对象的接口,且拜访类毋庸指定所要产品的具体类就能失去同族的不同等级的产品的模式构造。 形象工厂模式是工厂办法模式的降级版本,工厂办法模式只生产一个等级的产品,而形象工厂模式可生产多个等级的产品。 原型模式用一个曾经创立的实例作为原型,通过复制该原型对象来创立一个和原型对象雷同的新对象。 建造者模式将一个简单对象的构建与示意拆散,使得同样的构建过程能够创立不同的示意。拆散了部件的结构(由Buildler来负责)和拆卸(由Director责)。从而能够结构出简单的对象。这个模式实用于某个对象的构建过程简单的状况。 代理模式因为某些起因须要给某对象提供一个代理以管制对该对象的拜访。这时,拜访对象不适宜或者不能间接援用指标对象,代理对象作为拜访对象和指标对象之间的中介。Java中的代理依照代理类生成机会不同又分为动态代理和动静代理。动态代理代理类在编译期就生成,而动静代理代理类则是在Java运行时动静生成。动静代理又有JDK代理和CGLib代理两种。 适配器模式将一个类的接口转换成客户心愿的另外一个接口,使得本来因为接口不兼容而不能一起工作的那些类能一起工作。 装璜者模式在不扭转现有对象构造的状况下,动静地给该对象减少一些职责(即减少其颜外性能)的模式。 桥接模式将形象与实现拆散,使它们能够独立变动。它是用组合关系代替继承关系来实现,从而升高了形象和实现这两个可变维度的耦合度。 外观模式又名门面模式,是一种通过为多个简单的子系统提供一个统一的接口,而使这些子系统更加容易被拜访的模式。该模式对外有一个对立接口,内部应用程序不必关怀外部子系统的具体的细节,这样会大大降低应用程序的复杂度,进步了程序的可维护性。外观(Facade)模式是“迪米特法令”的典型利用。 组合模式又名局部整体模式,是用于把一组类似的对象当作一个繁多的对象。组合模式根据树形构造来组合对象,用来示意局部以及整体档次。这种类型的设计模式属于结构型模式,它创立了对象组的树形构造。 享元模式使用共享技术来无效地反对大量细社度对象的复用。它通过共享曾经存在的对象来大幅度缩小须要创立的对象数量、防止大量类似对象的开销,从而进步系统资源的利用率。 模板办法模式在面向对象程京设计过程中,程序员经常会遇到这种状况:设计一个零碎时晓得了算法所需的关键步骤,而且确定了这些步骤的执行程序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相干。定义一个操作中的算法骨架,而将算法的一些步骤提早到子类中,使得子类能够不扭转该算法构造的状况下重定义该算法的某些特定步骤。 策略模式该模式定义了一系列算法,并将每个算法封装起来,使它们能够互相替换,且算法的变动不会影响应用算法的客户。策略模式属于对象行为模式。它通过对算法进行封装,把应用算法的责任和算法的实现宰割开来,并委派给不同的对象对这些算法进行治理。 命令模式将一个申请封装为一个对象,使发出请求的责任和执行申请的责任宰割开。这样两者之问通过命令对象进行沟通,这样不便将命令对象进行存储,传递、调用、减少与治理。 职责链模式又名职责链模式,为了防止申请发送者与多个申请解决者耦合在一起,将所有申请的解决者通过前一对象记住其下一个对象的援用而连成一条链,当有申请产生时,可将申请沿着这条链传递,直到有对象解决它为止。 状态模式对有状态的对象,把简单的“判断逻辑”提取到不同的状态对象中,容许状态对象在其外部状态产生扭转时扭转其行为。 观察者模式又被称为公布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变动时,会告诉所有的观察者对象,使他们可能自动更新本人。 中介者模式又叫调解模式,定义一个中介角色来封装一系列对象之间的交互,使原有对象之间的耦合涣散,且能够独立地扭转它们之间的交互。 迭代器模式提供一个对象来程序拜访聚合对象中的一系列数据,而不裸露聚合对象的外部示意。 访问者模式封装一些作用于某种数据结构中的各元素的操作,它能够在不扭转这个数据结构的前提下定义作用于这些元素的新的操作。 备忘录模式又叫快照模式,在不毁坏封装性的前提下,捕捉一个对象的外部状态,并在该对象之外保留这个状态,以便当前当须要时能将该对象复原到原先保留的状态。 解择器模式给定一个语言,定义它的文法示意,并定义一个解释器,这个解释器应用该标识来解释语言中的句子。 关键词:java培训

February 16, 2022 · 1 min · jiezi

关于设计模式:轻松搞懂设计模式观察者模式

【设计模式】观察者模式前言观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态产生扭转时,所有依赖于它的对象都失去告诉并被自动更新。这种模式有时又称作公布-订阅模式、模型-视图模式,它是对象行为型模式。观察者模式是一种对象行为型模式,其次要长处如下: 升高了指标与观察者之间的耦合关系,两者之间是形象耦合关系。合乎依赖倒置准则。指标与观察者之间建设了一套触发机制。它的次要毛病如下: 指标与观察者之间的依赖关系并没有齐全解除,而且有可能呈现循环援用。当观察者对象很多时,告诉的发布会破费很多工夫,影响程序的效率。生存小案列举例说明:领导创立了一个名为摸鱼先锋队的群,用于团建事项的告诉,领导当晚公布了一条音讯--这次团建新入职的员工须要筹备表演节目。这个时候群里所有人都能看到这条音讯,只有新员工收到这个告诉后会有一系列表演的筹备工作要做,然而这条音讯对老员工没有任何的影响。这就是一个观察者模式的生存案例。当领导有事的时候公布告诉到群里,群里的所有人收到告诉后做相应的事件。以上案例中能够分为上面几个角色: 监听者(也能够说是观察者):群外面每一个人都是一个监听者。管理者(对应其余教程中的主题-subject):也就是群,次要有增加(群成员)监听者,移除(群成员)监听者,还有告诉所有监听者的性能。事件(或者说告诉):也就是领导发到群外面的音讯是一个事件(或者说告诉)。通过下面的例子来整顿一下实现一个观察者模式的思路。看看一个流程:领导创立群将相干人员增加到群,而后向群外面公布一个告诉。群外面每个人看到这条音讯后,做相应的事件,当这个音讯与本人无关时,啥也不做。领导在这外面能够看做是应用程序的一个线程,只是程序执行的一个单元而已。接下来就是个别设计模式都有的套路,为了程序的扩展性。下面的几个角色都须要定义成形象的概念,那么在Java外面定义形象有两种一个是接口一个是抽象类。具体定义成接口还是抽象类依据理论状况自行抉择。 抽象概念为什么要定义成形象的呢?咱们先理解一下形象的概念,我了解形象就是对一类事物公共局部的定义。比如说水果,就是对一类事物的形象定义,说到水果,大家必定能联想到,多汁且次要味觉为甜味和酸味,可食用的动物果实,有丰盛的营养成分。这个就是水果的公共成分,然而水果又分为多种,火龙果,百香果···。形象的益处:比方明天你家里只有一种水果-火龙果。你爹叫你拿一点水果来吃,那你必定就能间接把家里惟一的水果火龙果拿过去孝顺你老爹。在这个过程中你爹说的水果而不是火龙果,可能少说一个字从而节约能量多活一纳秒。那么咱们能够得出一个论断-应用抽象概念能够祛病延年→_→。开个玩笑,上面言归正传,我说一下我认为形象的益处: 当接口只定义一个实现类时,不便性能的替换(换一个实现类,在新实现类新增性能。从而防止了对调用方和原实现类原代码的改变)。办法形参定义为形象,这时就能实现传入不同的实现类该办法能够实现不同的性能。对立治理,让程序更规范化,当形象中定义新的非形象办法,子类能够间接继承应用。有了下面的铺垫,很容易了解上面的代码示例。 观察者模式代码示例代码地址:https://gitee.com/kangarookin...瞎编业务:用户购买商品后,应用观察者模式给相应用户增加积分。用户会员到期,应用观察者模式给相应用户发送短信。注:这里的业务是瞎编乱造的,结尾会给大家提供几个观察者模式在真正企业外面应用的场景。观察者模式其实也是公布订阅模式。针对不同的观察者须要有不同的实现形式,所以先创立一个管理者的接口,将其定义为一个抽象概念,不便后续扩大。这个接口相当于-群(管理者) /** * 观察者的顶层接口 * @param <T> */public interface ObserverInterface<T> { //注册监听者 public void registerListener(T t); //移除监听者 public void removeListener(T t); //告诉监听者 public void notifyListener(DataEvent t);}定义形象的监听者接口这个接口相当于-群成员(监听者) /** * Listener的顶级接口,为了形象Listener而存在 */public interface MyListener { void onEvent(DataEvent event);}定义形象的事件接口这个接口相当于群外面公布的告诉 @Datapublic abstract class DataEvent { private String msg;}创立管理者的实现类,相当于具体的群(如微信群,钉钉群) /** * 循环调用形式的观察者(同步) */@Componentpublic class LoopObserverImpl implements ObserverInterface<MyListener> { //监听者的注册列表 private List<MyListener> listenerList = new ArrayList<>(); @Override public void registerListener(MyListener listener) { listenerList.add(listener); } @Override public void removeListener(MyListener listener) { listenerList.remove(listener); } @Override public void notifyListener(DataEvent event) { for (MyListener myListener : listenerList) { myListener.onEvent(event); } }}创立两个event的实现类,一个是积分事件,一个是短信事件 ...

February 10, 2022 · 2 min · jiezi

关于设计模式:设计模式之装饰器模式

利用场景装璜器模式次要解决继承关系过于简单的问题,通过组合来代替继承。它次要的作用是给原始类增加加强性能。 装璜器模式有一个特点,那就是能够对原始类嵌套应用多个装璜器。为了满足这个利用场景,在设计的时候,装璜器类须要跟原始类继承雷同的抽象类或者接口。 聊聊Java IO类Java IO 类库十分宏大和简单,有几十个类,负责 IO 数据的读取和写入。咱们能够把IO类分为四类。 字节流字符流输出流InputStreamReader输入流OutputStreamWriter针对不同的读取和写入场景,Java IO 又在这四个父类根底之上,扩大出了很多子类。 置信大多数开发者在首次接触Java IO类时面对宏大的Java IO类家族产生困惑:为什么会有如此多的类?他们应用上有啥区别? 这里以读取 config.properties 文件为例,InputStream 是一个抽象类,FileInputStream 是专门用来读取文件流的子类。BufferedInputStream 是一个反对带缓存性能的数据读取类,能够进步数据读取的效率。 InputStream in = new FileInputStream("config.properties");InputStream bin = new BufferedInputStream(in);byte[] data = new byte[128];while (bin.read(data) != -1) { //...}Java IO 为什么不设计一个继承 FileInputStream 并且反对缓存的BufferedFileInputStream 类呢?这样咱们就能够间接创立new BufferedFileInputStream() 简略许多。 继承的问题事实上如果只是扩大这一个类,那还能够承受,然而InputStream具备很多子类,如果咱们持续依照继承的形式来实现的话,就须要再持续派生出 DataFileInputStream、DataPipedInputStream 等类。如果咱们还须要既反对缓存、又反对依照根本类型读取数据的类,那就要再持续派生出 BufferedDataFileInputStream、BufferedDataPipedInputStream 等 n 多类。这还只是附加了两个加强性能,如果咱们须要附加更多的加强性能,那就会导致组合爆炸,类继承构造变得无比简单,代码既不好扩大,也不好保护。 所以Java的设计者没有应用继承的形式来进行扩大,而是应用组合,这里也体现了组合优于继承的设计准则。上面是简化的JDK源码 public abstract class InputStream { // ...}public class BufferedInputStream extends InputStream { protected volatile InputStream in; public BufferedInputStream(InputStream in) { this.in = in; } // 实现基于缓存的读取...}public class DataInputStream extends InputStream { protected volatile InputStream in; public BufferedInputStream(InputStream in) { this.in = in; } // 实现读取根本数据类型...}如果去查看 JDK 的源码,你会发现,BufferedInputStream、DataInputStream 并非继承自 InputStream,而是另外一个叫 FilterInputStream 的类。 ...

January 29, 2022 · 2 min · jiezi

关于设计模式:设计模式之桥接模式

在 GoF 的《设计模式》一书中,桥接模式被定义为:“将形象和实现解耦,让它们能够独立变动。”定义中的“形象”,指的并非“抽象类”或“接口”,而是被形象进去的一套“类库”,它只蕴含骨架代码,真正的业务逻辑须要委派给定义中的“实现”来实现。而定义中的“实现”,也并非“接口的实现类”,而是一套独立的“类库”。 利用场景零碎可能有多个维度,每个维度都有可能变动。 类图 将Color类组合在Shape中来将形态和色彩解耦,各自保护各自的变动,这里体现了组合优于继承的设计准则。 桥接模式的引入会减少零碎的了解与设计难度,因为聚合关联关系建设在形象层,要求开发者针对形象进行设计与编程。 代码实现Color public abstract class Color { public abstract void paint(String shape);}Red public class Red extends Color { @Override public void paint(String shape) { System.out.println("红色的" + shape); }}Green public class Green extends Color { @Override public void paint(String shape) { System.out.println("绿色的" + shape); }}Shape public abstract class Shape { protected Color color; public void setColor(Color color) { this.color = color; } public abstract void draw();}Circle ...

January 27, 2022 · 1 min · jiezi

关于设计模式:设计模式之代理模式

代理模式是一种结构型设计模式。结构型模式次要总结了一些类或对象组合在一起的经典构造,这些经典的构造能够解决特定利用场景的问题。结构型模式包含:代理模式、桥接模式、装璜器模式、适配器模式、门面模式、组合模式、享元模式。代理模式的利用场景业务零碎的非功能性需要开发。比方:监控、统计、鉴权、限流、事务、幂等、日志。咱们将这些附加性能与业务性能解耦,放到代理类中对立解决,让程序员只须要关注业务方面的开发。RPC、缓存中利用。RPC 框架也能够看作一种代理模式;假如咱们要开发一个接口申请的缓存性能,对于某些接口申请,如果入参雷同,在设定的过期工夫内,间接返回缓存后果,而不必从新进行逻辑解决。代理模式分为动态代理和动静代理。动态代理的代理对象,在程序编译时曾经写好 Java 文件了,间接 new 一个代理对象即可。动静代理产生代理对象的机会是运行时动静生成,它没有 Java 源文件,间接生成字节码文件实例化代理对象。 动态代理的实现有两种:通过接口和通过继承。 动态代理 - 通过接口方式类图 代码实现UserServicepublic interface UserService { public Boolean login(String username, String password);}UserServiceImplpublic class UserServiceImpl implements UserService { @Override public Boolean login(String username, String password) { return "admin".equals(username) && "admin".equals(password); }}UserServiceProxypublic class UserServiceProxy implements UserService { private final UserService userService; public UserServiceProxy(UserService userService) { this.userService = userService; } @Override public Boolean login(String username, String password) { long t1 = System.nanoTime(); System.out.println("start login"); Boolean result = userService.login(username, password); System.out.println("end login"); long t2 = System.nanoTime(); System.out.println("time: " + (t2 - t1) + "ns"); return result; }}Mainpublic class Main { public static void main(String[] args) { UserService userService = new UserServiceProxy(new UserServiceImpl()); Boolean result = userService.login("admin", "admin"); System.out.println("result: " + result); }}动态代理 - 通过继承形式类图 ...

January 26, 2022 · 2 min · jiezi

关于设计模式:设计模式之原型模式

应用场景如果 对象的创立老本比拟大,而 同一个类的不同对象之间差异不大(大部分字段都雷同),在这种状况下,咱们能够利用对已有对象(原型)进行复制(或者叫拷贝)的形式来创立新对象,以达到节俭创立工夫的目标。 何为“对象的创立老本比拟大”?如果对象中的数据须要通过简单的计算能力失去(比方排序、计算哈希值),或者须要从 RPC、网络、数据库、文件系统等十分慢速的 IO 中读取,这种状况下,咱们就能够利用原型模式,从其余已有对象中间接拷贝失去,而不必每次在创立新对象的时候,都反复执行这些耗时的操作。 原型模式的实现形式:深拷贝和浅拷贝要应用原型模式,咱们就须要对对象进行拷贝,这里咱们要先理解下深拷贝和浅拷贝。 浅拷贝和深拷贝的区别在于,浅拷贝只会复制数据的内存地址,而深拷贝会复制数据自身。因而,浅拷贝与原始对象共享数据对象,原始对象如果批改了数据值,拷贝的对象也会变为新的值;而深拷贝失去的是一份完完全全独立的对象,不会受原对象影响。 在 Java 语言中,Object 类的 clone() 办法执行的就是咱们刚刚说的浅拷贝。它只会拷贝对象中的根本数据类型的数据(比方,int、long),以及援用对象的内存地址,不会递归地拷贝援用对象自身。 那如何实现深拷贝呢?递归拷贝对象、对象的援用对象以及援用对象的援用对象……直到要拷贝的对象只蕴含根本数据类型数据,没有援用对象为止。先将对象序列化,而后再反序列化成新的对象。

January 25, 2022 · 1 min · jiezi

关于设计模式:设计模式之建造者模式

应用场景对象的构建有很多必填参数,如果应用构造函数会导致参数列表过长难以使用结构参数之间有依赖关系,比方设置了minAge就必须设置maxAge,且minAge小于等于maxAge类的属性一旦被创立就不可变(不暴力set()办法)类图 Person类蕴含了一个外部类Builder,负责对外裸露设置属性的办法,这些办法能够蕴含校验和初始化规定,属性之前的依赖规定能够放到最终调用的build()办法中校验 代码实现public class Person { private Long id; private String name; private Integer minAge; private Integer maxAge; private Person() { } public static class Builder { private Person person = new Person(); public Builder id(Long id) { person.id = id; return this; } public Builder name(String name) { person.name = name; return this; } public Builder minAge(Integer minAge) { person.minAge = minAge; return this; } public Builder maxAge(Integer maxAge) { person.maxAge = maxAge; return this; } public Person build() { if (person.minAge != null && person.maxAge != null) { if (person.minAge < 0) { throw new IllegalArgumentException("minAge必须大于等于0"); } if (person.maxAge <= person.minAge) { throw new IllegalArgumentException("maxAge必须大于等于minAge"); } } else if ((person.minAge == null && person.maxAge != null) || (person.minAge != null && person.maxAge == null)) { throw new IllegalArgumentException("minAge和maxAge必须同时设置"); } return person; } }}与工厂模式有何区别?工厂模式是用来创立不同然而相干类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创立哪种类型的对象。建造者模式是用来创立一种类型的简单对象,通过设置不同的可选参数,“定制化”地创立不同的对象。

January 25, 2022 · 1 min · jiezi

关于设计模式:设计模式之单例模式

单例设计模式了解起来非常简单。一个类只容许创立一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫单例模式。 应用场景解决资源拜访抵触上面的示例中如果每个类都创立一个 Logger 实例,就可能造成日志内容被笼罩的状况。 public class Logger { private FileWriter writer; public Logger() { File file = new File("log.txt"); writer = new FileWriter(file, true); //true示意追加写入 } public void log(String message) { writer.write(mesasge); }}public class UserController { private Logger logger = new Logger(); public void login(String username, String password) { // ...省略业务逻辑代码... logger.log(username + " logined!"); }}public class OrderController { private Logger logger = new Logger(); public void create(OrderVo order) { // ...省略业务逻辑代码... logger.log("Created an order: " + order.toString()); }}示意全局惟一类如果有些数据在零碎中只应保留一份,那就比拟适宜设计为单例类。比方,配置信息类,全局 ID 生成器等。 ...

January 24, 2022 · 2 min · jiezi

关于设计模式:设计模式之工厂模式

工厂模式能够细分为:简略工厂、工厂办法和形象工厂三种模式 应用场景总体而言工厂模式的应用场景分为两种: 单个对象的创立过程比较复杂,如须要做简单初始化操作的对象须要依据不同的类型创立不同的对象针对细分的三种模式,应用场景又能够辨别: 当对象的创立逻辑简略,通常只须要new一下就能够,此时能够思考简略工厂模式当对象的创立逻辑很简单,须要做各种初始化操作,此时能够思考应用工厂办法模式,将对象创立的简单逻辑拆分到各个工厂类中,让每个工厂类都不至于过于简单当零碎中有多于一个产品族,而每次只应用其中某一产品族,此时应用形象工厂模式简略工厂模式类图 ProcuctA和ProductB继承Product抽象类,ProductFactory依据传入的type来返回不同的Product实例 代码实现Productpublic abstract class Product { public abstract void use();}ProductApublic class ProductA extends Product { @Override public void use() { System.out.println("You are using ProductA..."); }}ProductBpublic class ProductB extends Product { @Override public void use() { System.out.println("You are using ProductB..."); }}ProductFactorypublic class ProductFactory { public Product createProduct(String type) { Product product = null; if ("A".equals(type)) { product = new ProductA(); } else if ("B".equals(type)) { product = new ProductB(); } return product; }}Mainpublic class Main { public static void main(String[] args) { ProductFactory factory = new ProductFactory(); Product product; product = factory.createProduct("A"); product.use(); product = factory.createProduct("B"); product.use(); }}点评当频繁的新增不同产品时,须要频繁的批改ProductFactory中的if/else逻辑 ...

January 24, 2022 · 2 min · jiezi

关于设计模式:设计模式面试小炒策略和工厂模式替代业务场景中复杂的ifelse

《设计模式面试小炒》策略和工厂模式代替业务场景中简单的ifelse我是肥哥,一名不业余的面试官! 我是囧囧,一名踊跃找工作的小菜鸟! 囧囧示意:小白面试最怕的就是面试官问的知识点太抽象,本人无奈疾速定位到关键问题点!!!本期次要面试考点 面试官考点之如何用设计模式替换业务场景中简单的ifelse? VIP类型 import java.util.Objects;/** * @author: 欢送关注喂信公猪号:囧么肥事 * @date: 2021/12/16 * @email: jiongmefeishi@163.com * * 会员类型 */public enum VIPEnums { GOLD(1, "黄金会员"), STAR(2, "星钻会员"), SPORTS(3, "体育会员"), FUN_VIP(4, "FUN会员"); private final int code; private final String desc; VIPEnums(int code, String desc) { this.code = code; this.desc = desc; } public int getCode() { return code; } public String getDesc() { return desc; } public static VIPEnums getByCode(Integer code) { for (VIPEnums s : VIPEnums.values()) { if (Objects.equals(s.getCode(), code)) { return s; } } return null; }}VIP实体 ...

January 18, 2022 · 4 min · jiezi

关于设计模式:设计模式之设计原则

SOLID准则是由五个设计准则组成:繁多职责准则(SRP),开闭准则(OCP),里式替换准则(LSP),接口隔离准则(ISP),依赖反转准则(DIP)繁多职责准则(SRP)概念繁多职责准则的英文是 Single Responsibility Principle,缩写为 SRP。 一个类只负责实现一个职责或者性能。不要设计大而全的类,要设计粒度小、性能繁多的类。繁多职责准则是为了实现代码高内聚、低耦合,进步代码的复用性、可读性、可维护性。 如何判断类的职责是否足够繁多?不同的利用场景、不同阶段的需要背景、不同的业务层面,对同一个类的职责是否繁多,可能会有不同的断定后果。 一些侧面的判断指标更具备指导意义和可执行性,比方,呈现上面这些状况就有可能阐明这类的设计不满足繁多职责准则: 类中的代码行数、函数或者属性过多;类依赖的其余类过多,或者依赖类的其余类过多;公有办法过多;比拟难给类起一个适合的名字;类中大量的办法都是集中操作类中的某几个属性。类的职责是否设计得越繁多越好?繁多职责准则是为了实现代码高内聚、低耦合,如果拆分得过细,实际上会事与愿违,反倒会升高内聚性,也会影响代码的可维护性。 开闭准则(OCP)概念开闭准则的英文全称是 Open Closed Principle,简写为 OCP。 软件实体(模块、类、办法等)应该“对扩大凋谢、对批改敞开”。 增加一个新的性能,应该是通过在已有代码根底上扩大代码(新增模块、类、办法、属性等),而非批改已有代码(批改模块、类、办法、属性等)的形式来实现。对于定义,咱们有两点要留神。第一点是,开闭准则并不是说齐全杜绝批改,而是以最小的批改代码的代价来实现新性能的开发。第二点是,同样的代码改变,在粗代码粒度下,可能被认定为“批改”;在细代码粒度下,可能又被认定为“扩大”。 如何做到“对扩大凋谢、批改敞开”?咱们要时刻具备扩大意识、形象意识、封装意识,在写代码的时候,多思考这段代码将来可能有哪些需要变更,如何设计代码构造,当时留好扩大点,以便将新的代码灵便地插入到扩大点上。 23 种经典设计模式,大部分都是为了解决代码的扩展性问题而总结进去的,都是以开闭准则为领导准则的。最罕用来进步代码扩展性的办法有:多态、依赖注入、基于接口而非实现编程,以及大部分的设计模式(比方,装璜、策略、模板、职责链、状态)。 里式替换准则(LSP)概念里式替换准则的英文翻译是:Liskov Substitution Principle,缩写为 LSP。 子类对象可能替换程序中父类对象呈现的任何中央,并且保障原来程序的逻辑行为不变及正确性不被毁坏。 里式替换准则是用来领导,继承关系中子类该如何设计的一个准则。了解里式替换准则,最外围的就是了解“design by contract,依照协定来设计”这几个字。父类定义了函数的“约定”(或者叫协定),那子类能够扭转函数的外部实现逻辑,但不能扭转函数原有的“约定”。这里的约定包含:函数申明要实现的性能;对输出、输入、异样的约定;甚至包含正文中所列举的任何非凡阐明。 里式替换准则跟多态的区别尽管从定义形容和代码实现上来看,多态和里式替换有点相似,但它们关注的角度是不一样的。多态是面向对象编程的一大个性,也是面向对象编程语言的一种语法。它是一种代码实现的思路。而里式替换是一种设计准则,用来领导继承关系中子类该如何设计,子类的设计要保障在替换父类的时候,不扭转原有程序的逻辑及不毁坏原有程序的正确性。 接口隔离准则(ISP)概念接口隔离准则的英文翻译是“ Interface Segregation Principle”,缩写为 ISP。 客户端不应该强制依赖它不须要的接口。其中的“客户端”,能够了解为接口的调用者或者使用者。 接口的设计要尽量繁多,不要让接口的实现类和调用者,依赖不须要的接口函数。 接口隔离准则与繁多职责准则的区别繁多职责准则针对的是模块、类、接口的设计。接口隔离准则绝对于繁多职责准则,一方面更侧重于接口的设计,另一方面它的思考角度也是不同的。接口隔离准则提供了一种判断接口的职责是否繁多的规范:通过调用者如何应用接口来间接地断定。如果调用者只应用局部接口或接口的局部性能,那接口的设计就不够职责繁多。 依赖反转准则(DIP)概念依赖反转准则。依赖反转准则的英文翻译是 Dependency Inversion Principle,缩写为 DIP。 高层模块不要依赖低层模块。高层模块和低层模块应该通过形象来相互依赖。除此之外,形象不要依赖具体实现细节,具体实现细节依赖形象。 所谓高层模块和低层模块的划分,简略来说就是,在调用链上,调用者属于高层,被调用者属于低层。 管制反转(IOC)这里的“管制”指的是对程序执行流程的管制,而“反转”指的是在没有应用框架之前,程序员本人管制整个程序的执行。在应用框架之后,整个程序的执行流程能够通过框架来管制。流程的控制权从程序员“反转”到了框架。 实现管制反转的办法有很多,管制反转并不是一种具体的实现技巧,而是一个比拟抽象的设计思维,个别用来领导框架层面的设计。 依赖注入(DI)什么是依赖注入呢?咱们用一句话来概括就是:不通过 new() 的形式在类外部创立依赖类对象,而是将依赖的类对象在内部创立好之后,通过构造函数、函数参数等形式传递(或注入)给类应用。 KISS 准则概念KISS 准则。英文是 Keep It Simple and Stupid,缩写为 KISS。 尽量放弃简略 KISS 准则中的“简略”并不是以代码行数来考量的。代码行数越少并不代表代码越简略,咱们还要思考逻辑复杂度、实现难度、代码的可读性等。而且,自身就简单的问题,用简单的办法解决,并不违反 KISS 准则。除此之外,同样的代码,在某个业务场景下满足 KISS 准则,换一个利用场景可能就不满足了。 对于如何写出满足 KISS 准则的代码不要应用共事可能不懂的技术来实现代码;不要反复造轮子,要长于应用曾经有的工具类库;不要适度优化。DRY 准则概念DRY 准则为Don’t Repeat Yourself ...

January 14, 2022 · 1 min · jiezi

关于设计模式:设计模式7-探索一下桥接模式

设计模式,写代码必备神器... 桥接模式是什么?桥接模式是把抽象化和实现化解耦,让两者能够独立,该设计模式属于结构性设计模式。何为将抽象化和实现化解耦,能够了解为将性能点形象进去,性能的实现如何取决于不同的需要,然而形象的性能点(接口)曾经被桥接到本来的类型上,只用关注与实现。本来的类型变动,和形象的性能点能够自在变动,两头的桥梁曾经搭建起来了。 桥接模式其实就是不单单应用类继承的形式,而是重点应用类聚合的形式,进行桥接,把形象的性能点,聚合(注入)到基类外面。 桥接模式的益处个别用于解决什么问题呢? 次要是性能点实现品种多,多个维度的性能点,独立变动,没有什么关联,能够依照维度来治理。比方有 2 个维度,每个维度有 3 种实现,然而不同的维度之间其实没有关联,如果依照维度之间两两关联来搞,单单是实现类的数量就曾经2 * 3 = 6个类了,是在不太适合,还耦合在一块。 用电脑举个例子,既会分成不同的品牌,比方戴尔,联想,又会分为台式机,笔记本,那么不同的类就会很多,性能可能比拟反复。正是鉴于这一点,咱们得剥离反复的性能,用桥接的形式,来保护形象进去的独特性能点。 如果再新增一个品牌,比方,华硕,那么又得减少两个类,这显著不太适合,不同的类很多性能可能会反复。 那么桥接模式怎么解决呢?桥接模式把两个不同的维度 台式机 和 笔记本抽取进去,相当于作为一个通用的属性来保护。 代码Demo演示首先,定义一个形象的电脑类AbstractComputer,在其中有一个属性是ComputerType,示意电脑的类型: public abstract class AbstractComputer { protected ComputerType type; public void setType(ComputerType type) { this.type = type; } public abstract void work();}再定义三种类型的电脑:LenovoComputer,AsusComputer,DellComputer: public class LenovoComputer extends AbstractComputer{ @Override public void work() { System.out.print("联想"); type.feature(); }}public class AsusComputer extends AbstractComputer{ @Override public void work() { System.out.print("华硕"); type.feature(); }}public class DellComputer extends AbstractComputer{ @Override public void work() { System.out.print("戴尔"); type.feature(); }}电脑类型这个维度同样须要一个抽象类ComputerType,外面有一个阐明性能的办法feature(): ...

January 5, 2022 · 1 min · jiezi

关于设计模式:手把手教你23种设计模式

相干常识 简略工厂模式(不属于GoF 23 种设计模式) 工厂办法模式 形象工厂模式 单例模式 原型模式 建造者模式 代理模式 门面模式(外观模式) 装璜器模式 享元模式 组合模式(整体-局部模式) 【通明式】【 平安式】 适配器模式 【类适配器】 【对象适配器】 桥接模式 模板办法模式 策略模式 责任链模式(职责链模式) 迭代器模式 命令模式 状态模式 备忘录模式(快照模式) 中介者模式(调解模式) 解释器模式 访问者模式 观察者模式 委派模式(不属于GoF 23 种设计模式) 学习设计模式前,强烈建议先学习软件设计七大准则(https://blog.csdn.net/samllwi...) 相干常识《设计模式:可复用面向对象软件的根底》(Design Patterns: Elements of Reusable Object-Oriented Software)一书有4位作者,这 4 位作者在软件开发畛域里也以他们的“四人组”(Gang of Four,GoF)匿名著称。 23种设计模式依照目标分类:创立型模式、结构型模式和行为型模式 23种设计模式依照作用范畴分类:类模式和对象型模式 设计模式分类如下表: 范畴\目标创立型模式结构型模式行为型模式类模式工厂办法(Factory Method)模式(类)适配器(Adapter)模式模板办法(TemplateMethod)模式解释器(Interpreter)模式对象模式单例(Singleton)模式原型(Prototype)模式形象工厂(AbstractFactory)模式建造者(Builder)模式代理(Proxy)模式(对象)适配器(Adapter)模式桥接(Bridge)模式装璜(Decorator)模式外观(Facade)模式享元(Flyweight)模式组合(Composite)模式策略(Strategy)模式命令(Command)模式职责链(Chain of Responsibility)模式状态(State)模式观察者(Observer)模式中介者(Mediator)模式迭代器(Iterator)模式访问者(Visitor)模式备忘录(Memento)模式把设计模式英文也写上的起因是到时候看源码后缀,能够看出应用了什么设计模式 简略工厂模式(不属于GoF 23 种设计模式)含意:简单对象不禁用户间接创立,用工厂类进行创立 示例: 小米能够生产手机和电脑,都由工厂产生 public interface IProduct { void show();}public class MiComputer implements IProduct { public void show() { System.out.println("小米电脑"); }}public class MiPhone implements IProduct { public void show() { System.out.println("小米手机"); }}public class MiFactory { public static IProduct create(String type){ if ("phone".equals(type)){ return new MiPhone(); }else if ("computer".equals(type)){ return new MiComputer(); }else { return null; } }}public class TestMain { public static void main(String[] args) { IProduct miPhone = MiFactory.create("phone"); miPhone.show(); IProduct miComputer= MiFactory.create("computer"); miComputer.show(); }}类图: ...

December 30, 2021 · 25 min · jiezi

关于设计模式:设计模式建造者模式

1. 建造者模式概述应用多个简略对象来结构一个简单的对象。(1) 实用状况结构一个简单对象的外部组件不变,然而这些外部组建的组合形式常常变动的时候,能够思考应用建造者模式。 (2) 长处建造者独立,易扩大 (3) 毛病产品必须有共同点,范畴有限度不适用于外部组件常常产生变动的状况2. 建造者模式实例咱们当初要设计一个简略的外卖零碎,零碎中提供各种套餐,套餐中能够蕴含食物和饮料。(1) 先实现一个Item类,示意所有的食物和饮料的基类,它还实现了Packing接口,这样每个Item就能够进行打包了 public abstract class Item implements Packing { // 物品名称 private String name; // 物品价格 private int price; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; }}public interface Packing { // 打包 String packing();}(2) 外卖中能够包含食物Food和饮料Drink,它们都继承于Item类,且实现不同的打包形式 public abstract class Food extends Item implements Box { // 食物是用盒子打包}public abstract class Drink extends Item implements Bottle { // 饮料是用瓶子打包}(3) 打包形式能够分为盒装和瓶装 ...

December 14, 2021 · 2 min · jiezi

关于设计模式:设计模式单例模式

单例模式的意义:有一些对象咱们只须要一个实例,比如说线程池、缓存、对话框、日志对象、重放打印机、显卡等设施的驱动程序。这些对象只能有一个实例,否则会产生很多问题。为了确保只有一个实例,有时咱们通过全局变量的模式实现,然而将对象赋值给全局变量,然而却没有应用就会造成资源的节约。所以还只实例化一个实例更好。 总所周知,类对象的结构函默认是public类型的,这样我就是说这个对象能够有很多实例。当然咱们构造函数尽管不是私有的类型(如protected),只有同一个包的类能够实例化它时,然而仍能够实例化屡次, 公有的构造函数不能被类外实例化,只能类外部实例化。但很显然不可能通过类的实例来调用结构器,因为类实例的产生和结构器的调用就像"鸡生蛋,蛋生鸡"一样, 谁先谁后说不清楚。然而如果通过类用却是能够的。能够通过调用该类的静态方法,再通过静态方法调用公有的构造函数。一个简略的单例模式的实现如下:

December 9, 2021 · 1 min · jiezi

关于设计模式:设计模式策略模式

策略模式:定义了算法簇,别离封装起来,让它们之间能够相互替换,此模式让算法的变动能够独立于算法的客户。 具体实例:当初咱们要创立各种鸭子对象,这些鸭子有者不同的行为能力,会叫的,会飞的,不会叫的,不会飞的,飞得很快像火箭一样的等等。 咱们首先剖析鸭子的能力次要有两种,叫与飞。因而咱们将这两种能力剥离进去,定义为了接口。叫的差异化在叫的具体行为类来实现。飞的差异化能力在飞的具体类实现。 这样咱们就将接口与实现拆散了。 行为接口就像是一类算法,具体的行为类就是这类算法的差异化实现。当要扩大这类算法时,只须要增加新的行为类。 代码样例: 飞动作的行为接口public interface FlyBehavior { public void fly();}叫动作的行为接口public interface QuackBehavior { public void quack();}飞的具体行为类1public class FlyNoWay implements FlyBehavior{ @Override public void fly() { System.out.println("i cant not fly"); }}飞的具体行为类2public class FlyWithWings implements FlyBehavior{ @Override public void fly() { System.out.println("i am flying"); }}飞的具体行为类3public class FlyWithRocket implements FlyBehavior{ @Override public void fly() { System.out.println("i am flying with rocket"); }}叫的具体行为类1public class MuteQuack implements QuackBehavior{ @Override public void quack() { System.out.println("silence"); }}叫的具体行为类2public class Quack implements QuackBehavior{ @Override public void quack() { System.out.println("quack: gua gua gua"); }}抽象类Duck是具备叫和航行为的一类对象,咱们将Duck定义为了抽象类,在该类中蕴含了行为接口,通过行为接口对具体行为类的援用(多态),达到了行为的多态实现。 ...

December 9, 2021 · 2 min · jiezi

关于设计模式:设计模式抽象工厂模式

1. 形象工厂模式概述形象工厂就是工厂的工厂,把工厂形象成一个产品,那它的工厂就是形象工厂。 工厂模式用来生产产品,形象工厂用来生产工厂。 (1) 实用状况同一个产品族(大类)外面,蕴含多种产品(小类),每个产品对应一个工厂,那么产品族就对应一个形象工厂。 (2) 长处与工厂模式相似:屏蔽创立的具体细节、容易拓展产品 (3) 毛病扩大产品族艰难,要减少一个新产品,须要改变的中央较多 2. 形象工厂模式实例咱们接着工厂模式中的例子。咱们当初曾经领有了建造汽车的工厂,然而咱们还想建造火车怎么办?这里就能够应用形象工厂: (1) 先申明一个火车接口public interface Train { void declare();}(2) 创立各个品种的火车public class HighSpeed implements Train { @Override public void declare() { System.out.println("我是一辆高铁。"); }}public class LowSpeed implements Train { @Override public void declare() { System.out.println("我是一辆快车。"); }}(3) 申明形象工厂接口public interface AbstractFactory { // 用来生产汽车 Car buildCar(CAR_BRAND brand); // 用来生产火车 Train buildTrain(TRAIN_TYPE type);}(4) 创立工厂类,实现形象工厂接口public class TrainFactory implements AbstractFactory { @Override public Car buildCar(CAR_BRAND brand) { // 火车工厂不能生产汽车 return null; } @Override public Train buildTrain(TRAIN_TYPE type) { switch (type) { case HIGH_SPEED: return new HighSpeed(); case LOW_SPEED: return new LowSpeed(); default: return null; } }}enum TRAIN_TYPE { HIGH_SPEED, LOW_SPEED}(5) 创立工厂生成类,用来创立工厂public class FactoryProducer { public static AbstractFactory getFactory(String choice) { switch (choice) { case "Car": return new CarFactory(); case "Train": return new TrainFactory(); default: return null; } }}(6) 应用形象工厂创立汽车和火车public class FactoryDemo { public static void main(String[] args) { // 获取汽车工厂 AbstractFactory carFactory = FactoryProducer.getFactory("Car"); // 生产飞驰汽车 Car car = carFactory.buildCar(CAR_BRAND.BENZ); car.declare(); // 获取火车工厂 AbstractFactory trainFactory = FactoryProducer.getFactory("Train"); // 生产高铁 Train train = trainFactory.buildTrain(TRAIN_TYPE.HIGH_SPEED); train.declare(); }}运行后果: ...

December 8, 2021 · 1 min · jiezi

关于设计模式:设计模式单例模式

1. 单例模式介绍单例模式提供了一种创建对象的最佳形式。由某类负责创立本人的对象,并提供该对象的拜访形式,以确保该对象是该类惟一的实例。 (1) 实用状况:存在一个全局应用的类被频繁的创立和销毁时,能够思考应用单例模式。 (2) 长处:在堆中有且仅有一个实例,防止了频繁创立销毁以及保留的内存开销。 (3) 毛病:没有接口,不能继承。它在类的外部创立了本人的对象,这与繁多职责准则抵触,它原本不应该关怀内部是怎么实例化它的。 2. 单例模式实现(1) 懒汉式(线程不平安)先来看一种最简略的单例模式: public class Singleton { private static Singleton instance; // 公有构造方法 private Singleton() { } public static Singleton getSingleton() { if (instance == null) { instance = new Singleton(); } return instance; }}为什么叫懒汉,因为它不急着创立实例,而是等到断定为空的时候才去创立 它最大的问题就是线程不平安,因为可能会有多个线程断定instance == null,从而创立多个实例,严格意义上说,它并不能算单例模式。 (2) 懒汉式(线程平安)上边的实现是线程不平安的,那给getSingleton办法减少synchronized不就行了吗: public class Singleton { private static Singleton instance; // 公有构造方法 private Singleton() { } public static synchronized Singleton getSingleton() { if (instance == null) { instance = new Singleton(); } return instance; }}这样做的确是能够保障线程平安的,然而加锁会影响效率其实除了第一次须要创立之外,后续的加锁就没有意义了 ...

December 8, 2021 · 1 min · jiezi

关于设计模式:设计模式工厂模式

1. 工厂模式概述在工厂模式中,创建对象不会对外界裸露创立逻辑,而是通过应用一个独特的接口来获取新创建的对象。在工厂模式中,不须要外界手动创立一个实例,而是通过调用对象工厂的办法,返回该类的实例。 比方我当初想获取一个产品,我只须要调用这个产品的工厂的办法就能够了。 (1) 实用状况须要依据不同的条件,创立不同的实例对象时,能够思考应用工厂模式。 (2) 长处对于调用者来说,不用关怀实例的创立形式,这样能够屏蔽产品的具体实现拓展性高,如果须要减少一个产品,只须要拓展一个工厂类就能够(3) 毛病如果产品过多,则工厂类也会过多,减少了零碎的复杂度。 2. 工厂模式实现当初咱们须要一个汽车工厂,用来创立不同品牌的汽车对象。 (1) 先申明一个汽车接口public interface Car { void declare();}(2) 创立各个品牌汽车的实现类public class Benz implements Car{ @Override public void declare() { System.out.println("我是一辆飞驰。"); }}public class BMW implements Car{ @Override public void declare() { System.out.println("我是一辆宝马。"); }}public class Audi implements Car{ @Override public void declare() { System.out.println("我是一辆奥迪。"); }}(3) 创立汽车工厂public class CarFactory { /** * 生产汽车 * * @param brand 汽车品牌 * @return 汽车 */ public Car buildCar(CAR_BRAND brand) { switch (brand) { case BENZ: return new Benz(); case BMW: return new BMW(); case AUDI: return new Audi(); } return null; }}enum CAR_BRAND { BENZ, BMW, AUDI}(4) 应用汽车工厂生产汽车public class FactoryDemo { public static void main(String[] args) { CarFactory carFactory = new CarFactory(); // 生产一辆飞驰 Car benz = carFactory.buildCar(CAR_BRAND.BENZ); benz.declare(); // 生产一辆宝马 Car bmw = carFactory.buildCar(CAR_BRAND.BMW); bmw.declare(); // 生产一辆奥迪 Car audi = carFactory.buildCar(CAR_BRAND.AUDI); audi.declare(); }}运行后果: ...

December 7, 2021 · 1 min · jiezi

关于设计模式:设计模式概述

1. 设计模式概述设计模式(Design pattern)代表了最佳的实际,通常被有教训的面向对象的软件开发人员所采纳。设计模式是软件开发人员在软件开发过程中面临的个别问题的解决方案。这些解决方案是泛滥软件开发人员通过相当长的一段时间的试验和谬误总结进去的。以后遇到的问题,绝大多数都是前人曾经踩过的坑,他们总结了一系列 “套路”,来解决各种各样的问题。这些套路能够被重用,从而使得代码更容易被了解和拓展,并保障代码的可靠性。 就像是练武,只会一些拳脚功夫是不够的,还须要成体系的文治秘籍来死记硬背。这套文治秘籍会通知你遇到什么样的敌人应该应用什么招式,也会通知你应该如何去做才不至于走火入魔。设计模式的重要性显而易见,懂的都懂,学就完事了。 2. 设计模式分类经典的设计模式一共有23种(当然还有其余一些模式),这些设计模式依据目标能够被分为三大类: (1) 创立型模式这些设计模式提供了一种在创建对象的同时暗藏创立逻辑的形式,而不是应用 new 运算符间接实例化对象。这使得程序在判断针对某个给定实例须要创立哪些对象时更加灵便。单例模式:工厂办法模式:形象工厂模式:建造者模式:原型模式: (2) 结构型模式这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象取得新性能的形式。代理模式:适配器模式:桥接模式:装璜器模式:外观模式:享元模式:组合模式: (3) 行为型模式这些设计模式特地关注对象之间的通信。作用于类或对象之间相互协作共同完成单个对象无奈独自实现的工作,以及怎么调配职责。责任链模式:命令模式:解释器模式:迭代器模式:中介者模式:备忘录模式:观察者模式:状态模式:策略模式:模板办法模式:访问者模式: 3. 设计模式六大准则(1) 繁多职责准则(Single Responsibility Principle, SRP)对于一个类而言,应该只有一个引起它变动的起因。也就是说,一个类只负责一个性能,不能因为每次引入新性能,都要去批改这个类,除非是这个类自身产生了扭转。 (2) 开闭准则(Open-Closed Principle, OCP)一个软件实体该当对扩大凋谢,对批改敞开也就是说,尽量通过继承抽象类或者实现接口的形式来进行性能加强,而不是间接对原有代码进行批改。 (3) 里氏替换准则(Liskov Substitution Principle, LSP)所有援用基类(父类)的中央必须能通明地应用其子类的对象。也就是说,应该可能把应用父类的中央,间接替换成子类。这就要求尽量把父类设计为抽象类或者接口,且不要去重写父类中的办法,使其性能在所有子类中都雷同。 (4) 依赖倒置准则(Dependence Inversion Principle,DIP)高层模块不应该依赖低层模块,两者都应该依赖其形象;形象不应该依赖细节,细节应该依赖形象。也就是说,要面向接口编程,不要面向实现编程。 (5) 接口隔离准则(Interface Segregation Principle, ISP)应用多个专门的接口,而不应用繁多的总接口,即客户端不应该依赖那些它不须要的接口。也就是说,接口也是须要繁多职责的,不要把不相干的办法都申明在一个接口中,否则类就得实现这些它并不关怀的办法。 (6) 迪米特法令(Law of Demeter, LoD)一个软件实体该当尽可能少地与其余实体产生相互作用。也就是说,通过引入一个正当的第三者来升高现有对象之间的耦合。每个类的成员变量和办法,能不public就不public,防止被随便援用。

December 6, 2021 · 1 min · jiezi

关于设计模式:前端比较实用的设计模式总结

设计模式不分前端与后端,它是一种编程思维,无论在任何语言、任何环境中运行的程序,他们都会有一些雷同的设计思路。而咱们通过理解这些思维,能力进步本人的编程能力,写代码才会变成享受的事件。咱们不仅仅只是在实现工作,更是在发明一件作品,一件属于你本人的而且令人赏心悦目的艺术品。 - 我本人的了解设计准则做什么事都须要遵循一些准则,设计模式也不例外。咱们在设计一些设计模式时,个别遵循如下七项根本准则。 繁多职责准则 (Single Responsibility Principle)凋谢-敞开准则 (Open-Closed Principle)里氏替换准则 (Liskov Substitution Principle)依赖倒转准则 (Dependence Inversion Principle)接口隔离准则 (Interface Segregation Principle)起码晓得准则(The Least Knowledge Principle)组合/聚合复用准则 (Composite/Aggregate Reuse Principle)这些准则里,我认为比拟实用而且很重要的是:繁多职责准则、凋谢-敞开准则、起码晓得准则。因为有这些根本的准则作为公约,咱们的我的项目将会倒退的很衰弱,扩展性很强,具体解释一下这三个准则,其余准则有趣味能够本人搜寻一下,比拟好找。 繁多职责准则Single Responsibility Principle 一个对象或办法只做一件事件。如果一个办法承当了过多的职责,那么在需要的变迁过程中,须要改写这个办法的可能性就越大。应该把对象或办法划分成较小的粒度,进步代码可读性,进步零碎可维护性。凋谢-敞开准则Open for extension, close for modification 对扩大凋谢:有新的需要或变动时,能够对现有代码进行扩大,以适应新的状况。对批改关闭:一旦设计实现,模块的源代码不能被进犯,任何人不容许批改已有源代码。凋谢关闭的核心思想就是对形象编程,而不对具体编程,因为形象绝对稳固。让类依赖于固定的形象,所以对批改就是关闭的;而通过面向对象的继承和多态机制,能够实现对形象体的继承,通过覆写其办法来扭转固有行为,实现新的扩大办法,所以对于扩大就是凋谢的。起码晓得准则The Least Knowledge Principle 或者称迪米特法令(Law of Demeter),它形容了一种放弃代码松耦合的策略,每个单元对其余单元只领有无限的常识,只理解与以后单元紧密联系的单元;古代面向对象程序设计语言通常应用 "." 作为拜访标识,LoD 能够被简化为 "仅应用一个点(use only one dot)"。也就是说,代码 a.b.Method() 违反了 LoD,而 a.Method() 则合乎 LoD。打个比方,人能够命令一条狗行走,然而不应该间接指挥狗的腿行走,应该由狗去指挥它的腿行走。设计模式在 JS 设计模式中,最外围的思维:封装变动。将变与不变拆散,确保变动的局部灵便、不变的局部稳固。 结构器模式Constructor Pattern 特点: 结构器是一个当新建对象的内存被调配后,用来初始化该对象的一个非凡函数,在 JavaScript 中简直所有的货色都是对象。同时结构器能够应用的参数,以在第一次创建对象时,设置成员属性的办法的值。对象定义:状态、属性、行为示例代码: function GirlFriend(name, age, cup, height) { this.name = name; this.age = age; this.cup = cup; this.height = height;}GirlFriend.prototype.myIndentity = function () { console.log(`我是被发明进去的女朋友,我叫${this.name}`);};const aGirl = new GirlFriend('小A女朋友', 28, '36F', 'LOL');const bGirl = new GirlFriend('小B女朋友', 19, '36C', 'DOTA');模块模式Module Pattern 特点: ...

November 19, 2021 · 5 min · jiezi

关于设计模式:设计模式

六大准则参考链接 一、繁多职责准则(Single Responsibility Principle)应该有且仅有一个起因引起类的变更。 问题场景:类C负责两个不同的职责:职责D1,职责D2。当因为职责D1需要产生扭转而须要批改类C时,有可能会导致本来运行失常的职责D2性能产生故障。 繁多职责最难划分的就是职责,一个职责一个接口,但问题是”职责“没有一个量化的规范,一个类到底要负责哪些职责?这些职责怎么细化?细化后是否都要有一个接口或类?这些都须要从理论的我的项目去思考。 解决方案:遵循繁多职责准则。别离建设两个类C1、C2,使C1实现职责D1性能,C2实现职责D2性能。这样,当批改类C1时,不会使职责D2产生故障危险;同理,当批改C2时,也不会使职责D1产生故障危险。 比如说一个用户类,应该把用户的信息抽取成一个BO(Business Object,业务对象),把行为抽取成一个Biz(Business Logic,业务逻辑)。这样前者的职责是收集和反馈用户的属性信息;后者的职责是实现用户信息的保护和变更。分成这样的两个接口来设计之后,这两个职责的变动就不会相互影响。 繁多职责的益处:类的复杂性升高,实现什么职责都有清晰明确的定义;可读性进步;可维护性进步;变更引起的危险升高。变更是必不可少的,如果接口的的繁多职责做得好,一个接口批改只对相应的实现类有影响,对其余的接口无影响,这对系统的扩展性、维护性都有十分大的帮忙。 二、里氏替换准则(Liskov Substitution Principle)定义一(规范定义):如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。定义二(艰深定义):所有援用基类的中央必须能通明地应用其子类的对象。 从定义二中能够了解到,只有父类能呈现的中央子类就能够呈现,而且替换为子类也不会产生任何谬误或异样,使用者可能基本不须要晓得是父类还是子类。但反之就不行了。 里氏替换准则的标准:1. 子类必须齐全实现父类的办法在类中调用其余类时务必要应用父类或接口,如果不能应用父类或接口,则阐明类的设计曾经违反了LSP准则。 如果子类不能残缺地实现父类的办法,或者父类的某些办法在子类中曾经产生”畸变“,则倡议断开父子继承关系,采纳依赖、汇集、组合等关系代替继承。子类能够实现父类的形象办法,但不能笼罩父类的非形象办法。子类能够有本人的共性子类中能够减少本人特有的办法。因为子类可能有比父类多的属性和行为,所以向下转型是不平安的,从LSP来看,就是有子类呈现的中央父类未必就能够呈现。2. 笼罩或实现父类的办法时参数能够被放大LSP要求制订一个契约,就是父类或接口,这种设计办法也叫做Design by Contract。契约制订了,也就同时制订了前置条件(即办法的形参)和后置条件(即办法的返回值)。在理论利用中父类个别都是抽象类,子类是实现类,子类中办法的前置条件必须与超类中被覆写的办法的前置条件雷同或者更宽松。3. 覆写或实现父类的办法时输入构造能够被放大父类的一个办法的返回值是一个类型T,子类的雷同办法(重载或覆写)的返回值为S,那么LSP就要求S必须小于或等于T。三、依赖倒置准则(Dependence Inversion Principle)高层模块不应该依赖低层模块,二者都应该依赖其形象;形象不应该依赖细节;细节应该依赖形象。 问题场景:类A间接依赖于类B,如果要将类A改为依赖于类C,则必须通过批改类A的代码来达成。这种场景下,类A个别是高层模块,类B和类C是低层模块,如果批改了类A,可能会给程序带来不必要的危险。 解决方案:将类A批改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类或者类C产生分割,则会大大降低批改类A的几率。 依赖倒置准则的核心思想是面向接口编程。 依赖倒置准则基于这样一个事实:绝对于细节的多变性,形象的货色要稳固的多。以形象为根底搭建起来的架构比以细节为根底搭建起来的架构要稳固的多。在java中,形象指的是接口或者抽象类,细节就是具体的实现类,应用接口或者抽象类的目标是制订好标准和契约,而不去波及任何具体的操作,把展示细节的工作交给他们的实现类去实现。 依赖的三种写法:依赖是能够传递的,对象的依赖关系有三种形式来传递: 构造函数传递依赖对象。在类中通过构造函数申明依赖对象,依照依赖注入的说法,这种形式叫作构造函数注入;Setter办法传递依赖对象。在抽象类中设置Setter办法申明依赖关系,按照依赖注入的说法,这是Setter依赖注入;接口申明依赖对象。在接口的办法中申明依赖对象,这种办法也叫做接口注入。最佳实际:依赖倒置准则的实质就是通过形象(接口或抽象类)使各个类或模块的实现彼此独立,不相互影响,实现模块间的松耦合。在理论我的项目中,如何利用这个规定呢,只有遵循以下几个规定就能够: 每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备,这是依赖倒置的根本要求,有了形象才可能依赖倒置;变量的外表类型尽量是接口或者是抽象类;任何类都不应该从具体类派生;尽量不要覆写基类的办法;联合里氏替换准则应用:接口负责定义public属性和办法,并且申明与其余对象的依赖关系,抽象类负责公共结构局部的实现,实现类精确的实现业务逻辑,同时在适当的时候对父类进行细化。四、接口隔离准则(Interface Segregation Principle)客户端不应该依赖它不须要的接口;一个类对另一个类的依赖应该建设在最小的接口上。 接口分为两种: 实例接口:在Java中申明一个类,而后用new关键字产生一个实例,它是对一个类型的事物的形容,这是一种接口,从这个角度来看,Java中的类也是一种接口;类接口:Java中常常应用的interface关键字定义的接口。什么是隔离呢?它有两种定义: 客户端不应该依赖它不须要的接口;类间的依赖关系应该建设在最小的接口上。这两句话能够概括为一句话:建设繁多接口,不要建设臃肿宏大的接口。更艰深的讲:接口尽量细化,同时接口中的办法尽量少。 问题由来:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不须要的办法。 解决方案:将臃肿的接口I拆分为独立的几个接口,类A和类C别离与他们须要的接口建设依赖关系。也就是采纳接口隔离准则。 接口隔离准则 vs. 繁多职责准则:二者的扫视角度不同,繁多职责要求的是类和接口职责繁多,重视的是职责,这是业务逻辑上的划分,而接口隔离准则要求接口的办法尽量少,它要求“尽量应用多个专门的接口”。 最佳实际:接口要尽量小,一个接口只服务于一个子模块或业务逻辑,依据接口隔离准则拆分接口时,首先必须满足繁多职责准则;接口要高内聚,具体来讲就是在接口中尽量少颁布public办法,接口是对外的承诺,承诺越少对系统的开发越无利,变更的危险也就越少,同时也有利于降低成本;曾经被净化了的接口,尽量去批改,若变更的危险较大,则采纳适配器模式进行转化解决;定制服务:定制服务是独自为一个个体提供低劣的服务,要求是只提供访问者须要的办法;接口设计是有限度的:接口设计的粒度须要依据教训和常识进行正当的判断。五、迪米特法令(Least Knowledge Principle)一个对象应该对其余对象有起码的理解,即一个类应该对本人须要耦合或调用的类晓得得起码,只关注本人调用的public办法,其余的一律不关怀。 最佳实际:迪米特法令的核心思想就是类间解耦,弱耦合,只有弱耦合了当前,类的复用率才能够进步。其要求的后果就是产生了大量的直达或跳转类,导致系统的复杂性进步,同时也为保护带来了的难度。因而在采纳迪米特法令时,既要做到让构造清晰,又做到高内聚低耦合。 开闭准则一个软件实体类,如类、模块和函数应该对扩大凋谢,对批改敞开。 问题由来:开闭准则是一个十分虚的准则,后面5个准则是对开闭准则的具体解释,然而开闭准则并不局限于这么多。在理论工作中须要留神以下几点: 形象束缚:形象是对一组事物的通用形容,没有具体的实现,也就示意它能够有十分多的可能性,能够追随需要的变动而变动。因而接口或抽象类能够束缚一组可能变动的行为,并且可能实现对扩大凋谢。元数据管制模块行为:元数据是用来形容环境和数据的数据,艰深地讲就是配置参数,参数能够从文件中取得,也能够从数据库中取得,应用此办法的极致就是管制反转,应用最多的就是Spring容器。制订我的项目章程:对我的项目来说,约定优于配置。章程中指定了所有人员都必须恪守的约定。封装变动:将雷同的变动封装到一个接口或抽象类中;将不同的变动封装到不同的接口或抽象类中,不应该有两个不同的变动呈现在同一个接口或抽象类中。封装变动,也就是受爱护的变动,找出预计有变动或不稳固的点,为这些变动点创立稳固的接口。六大设计准则利用了解:从整体上来了解六大设计准则,能够简要的概括为一句话,用形象构建框架,用实现扩大细节,具体到每一条设计准则,则对应一条注意事项: 繁多职责准则通知咱们实现类要职责繁多;里氏替换准则通知咱们不要毁坏继承体系;依赖倒置准则通知咱们要面向接口编程;接口隔离准则通知咱们在设计接口的时候要精简繁多;迪米特法令通知咱们要升高耦合;开闭准则是总纲,通知咱们要对扩大凋谢,对批改敞开。恪守:了解了这六大设计准则之后,如何来恪守呢?制订这六条准则的目标并不是要咱们刻板的恪守,而是依据理论须要灵活运用。只有对它们的恪守水平在一个正当的范畴内,就算是良好的设计,用一幅图来阐明一下:图等会再说,并且还少了一个准则 23种设计模式

November 17, 2021 · 1 min · jiezi