关于设计模式:设计模式20-解释模式

1. 简介咱们来学习解释器模式,它用来形容如何构建一个简略的“语言”解释器。比起命令模式,解释器模式更加小众,只在一些特定的畛域会被用到,比方编译器、规定引擎、正则表达式。 解释器模式的英文翻译是 Interpreter Design Pattern。在 GoF 的《设计模式》一书中,它是这样定义的: Interpreter pattern is used to defines a grammatical representation for a language and provides an interpreter to deal with this grammar.翻译成中文就是:解释器模式为某个语言定义它的语法(或者叫文法)示意,并定义一个解释器用来解决这个语法。

August 11, 2020 · 1 min · jiezi

关于设计模式:设计模式19-备忘录模式

1. 简介这个模式了解、把握起来不难,代码实现比拟灵便,利用场景也比拟明确和无限,次要是用来防失落、撤销、复原等。 备忘录模式,也叫快照(Snapshot)模式,英文翻译是 Memento Design Pattern。在 GoF 的《设计模式》一书中,备忘录模式是这么定义的: Captures and externalizes an object’s internal state so that it can be restored later, all without violating encapsulation.翻译成中文就是: 在不违反封装准则的前提下,捕捉一个对象的外部状态,并在该对象之外保留这个状态,以便之后复原对象为先前的状态。一部分是,存储正本以便前期复原。另一部分是,要在不违反封装准则的前提下,进行对象的备份和复原。

August 11, 2020 · 1 min · jiezi

关于设计模式:设计模式18-访问者模式

1. 简介访问者者模式的英文翻译是 Visitor Design Pattern。 在 GoF 的《设计模式》一书中,它是这么定义的: Allows for one or more operation to be applied to a set of objects at runtime, decoupling the operations from the object structure.翻译成中文就是: 容许一个或者多个操作利用到一组对象上,解耦操作和对象自身。对于访问者模式的代码实现,实际上,在下面例子中,通过层层重构之后的最终代码,就是规范的访问者模式的实现代码。这里,我又总结了一张类图,贴在了上面,你能够对照着后面的例子代码一块儿来看一下。

August 10, 2020 · 1 min · jiezi

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

1. 简介它用来遍历汇合对象。不过,很多编程语言都将迭代器作为一个根底的类库,间接提供进去了。在平时开发中,特地是业务开发,咱们间接应用即可,很少会本人去实现一个迭代器。不过,知其然知其所以然,弄懂原理能帮忙咱们更好的应用这些工具类,所以,我感觉还是有必要学习一下这个模式。 迭代器模式(Iterator Design Pattern),也叫作游标模式(Cursor Design Pattern)。 迭代器是用来遍历容器的,所以,一个残缺的迭代器模式个别会波及容器和容器迭代器两局部内容。

August 6, 2020 · 1 min · jiezi

关于设计模式:设计模式学习笔记二十六访问者模式

1 概述1.1 引言患者就医时,医生开具处方后通常由药房工作人员筹备药品,由划价人员依据药品数量计算总价,这里,能够将处方看作是一个药品信息的汇合,外面蕴含了一种或多种不同类型的药品信息,不同类型的工作人员在操作同一个药品信息汇合时将提供不同的解决形式,而且可能还会减少新类型的工作人员来操作处方单。 在软件开发中,有时候也须要解决像处方单这样的汇合构造,在该对象构造中存储了多个不同类型的对象信息,而且对同一对象构造中的元素的操作形式不惟一,可能须要提供多种不同的解决形式,还有可能减少新的解决形式。这时候能够应用访问者模式进行解决。 访问者模式是一种较为简单的行为型设计模式,它蕴含访问者与被访问者两个次要组成部分,这些被拜访的元素通常具备不同的类型,且不同的访问者能够对它们进行不同的拜访操作。访问者模式使得用户能够在不批改现有零碎的状况下扩大零碎的性能,为这些不同类型的元素减少新的操作。 1.2 定义访问者模式:提供一个作用于某对象构造中的各元素的操作示意,它使得能够在不扭转各元素的类的前提下定义作用于这些元素的新操作。 访问者模式是一种对象行为型模式。 1.3 结构图 1.4 角色Visitor(形象访问者):为每一个具体元素类申明一个具体访问者的操作ConcreteVisitor(具体访问者):实现形象访问者中的操作Element(形象元素):接口/抽象类,定义一个accept办法示意承受访问者的拜访ConcreteElement(具体元素):实现了accept办法,在accept中调用访问者的拜访办法实现对具体元素的拜访ObjectStructure(对象构造):形象元素的汇合,用于寄存形象元素对象,提供了遍历外部元素的办法2 典型实现2.1 步骤定义形象元素:申明一个accept办法示意承受访问者拜访,由具体元素实现具体拜访操作定义具体元素:实现形象元素中的accept办法,同时定义拜访属性的办法供访问者调用定义对象构造:应用List或Set等存储形象元素汇合,蕴含治理汇合元素的办法,同时也蕴含accept办法,该办法会遍历元素并调用每个元素的accept办法定义形象访问者:申明visit办法,作为对具体元素的拜访办法,个别应用重载实现,也就是一个具体元素对应一个visit定义具体访问者:实现形象访问者中的拜访具体元素办法2.2 形象元素interface Element{ void accept(Visitor visitor);}这里实现为一个接口,蕴含一个accept办法,示意承受访问者的拜访。 2.3 具体元素class ConcreteElementA implements Element{ @Override public void accept(Visitor visitor) { visitor.visit(this); } public void show1() { System.out.println("用第一种形式拜访具体元素A"); } public void show2() { System.out.println("用第二种形式拜访具体元素A"); }}class ConcreteElementB implements Element{ @Override public void accept(Visitor visitor) { visitor.visit(this); } public void show1() { System.out.println("用第一种形式拜访具体元素B"); } public void show2() { System.out.println("用第二种形式拜访具体元素B"); }}这里定义了两个具体元素,重点是其中的accept办法,通过参数visitor,将本身(具体元素类)作为参数调用visit办法,以示意该访问者(visitor)拜访该元素(this)。这里波及到了"双分派",简略来说就是运行时确定形象访问者(visitor)以及形象元素(this)的具体类型,上面会有一大节具体阐明分派的概念。 ...

August 5, 2020 · 4 min · jiezi

关于设计模式:设计模式学习笔记二十六访问者模式

1 概述1.1 引言患者就医时,医生开具处方后通常由药房工作人员筹备药品,由划价人员依据药品数量计算总价,这里,能够将处方看作是一个药品信息的汇合,外面蕴含了一种或多种不同类型的药品信息,不同类型的工作人员在操作同一个药品信息汇合时将提供不同的解决形式,而且可能还会减少新类型的工作人员来操作处方单。 在软件开发中,有时候也须要解决像处方单这样的汇合构造,在该对象构造中存储了多个不同类型的对象信息,而且对同一对象构造中的元素的操作形式不惟一,可能须要提供多种不同的解决形式,还有可能减少新的解决形式。这时候能够应用访问者模式进行解决。 访问者模式是一种较为简单的行为型设计模式,它蕴含访问者与被访问者两个次要组成部分,这些被拜访的元素通常具备不同的类型,且不同的访问者能够对它们进行不同的拜访操作。访问者模式使得用户能够在不批改现有零碎的状况下扩大零碎的性能,为这些不同类型的元素减少新的操作。 1.2 定义访问者模式:提供一个作用于某对象构造中的各元素的操作示意,它使得能够在不扭转各元素的类的前提下定义作用于这些元素的新操作。 访问者模式是一种对象行为型模式。 1.3 结构图 1.4 角色Visitor(形象访问者):为每一个具体元素类申明一个具体访问者的操作ConcreteVisitor(具体访问者):实现形象访问者中的操作Element(形象元素):接口/抽象类,定义一个accept办法示意承受访问者的拜访ConcreteElement(具体元素):实现了accept办法,在accept中调用访问者的拜访办法实现对具体元素的拜访ObjectStructure(对象构造):形象元素的汇合,用于寄存形象元素对象,提供了遍历外部元素的办法2 典型实现2.1 步骤定义形象元素:申明一个accept办法示意承受访问者拜访,由具体元素实现具体拜访操作定义具体元素:实现形象元素中的accept办法,同时定义拜访属性的办法供访问者调用定义对象构造:应用List或Set等存储形象元素汇合,蕴含治理汇合元素的办法,同时也蕴含accept办法,该办法会遍历元素并调用每个元素的accept办法定义形象访问者:申明visit办法,作为对具体元素的拜访办法,个别应用重载实现,也就是一个具体元素对应一个visit定义具体访问者:实现形象访问者中的拜访具体元素办法2.2 形象元素interface Element{ void accept(Visitor visitor);}这里实现为一个接口,蕴含一个accept办法,示意承受访问者的拜访。 2.3 具体元素class ConcreteElementA implements Element{ @Override public void accept(Visitor visitor) { visitor.visit(this); } public void show1() { System.out.println("用第一种形式拜访具体元素A"); } public void show2() { System.out.println("用第二种形式拜访具体元素A"); }}class ConcreteElementB implements Element{ @Override public void accept(Visitor visitor) { visitor.visit(this); } public void show1() { System.out.println("用第一种形式拜访具体元素B"); } public void show2() { System.out.println("用第二种形式拜访具体元素B"); }}这里定义了两个具体元素,重点是其中的accept办法,通过参数visitor,将本身(具体元素类)作为参数调用visit办法,以示意该访问者(visitor)拜访该元素(this)。这里波及到了"双分派",简略来说就是运行时确定形象访问者(visitor)以及形象元素(this)的具体类型,上面会有一大节具体阐明分派的概念。 ...

August 5, 2020 · 4 min · jiezi

关于设计模式:设计模式学习笔记二十五模板方法模式

1 概述1.1 引言模板办法模式是构造最简略的行为型设计模型,在其构造中只存在父类与之类之间的继承关系,通过应用模板办法模式,能够将一些简单流程的实现步骤封装在一系列根本办法中,在形象父类提供一个称之为模板办法的办法来定义这些根本办法的执行秩序,而通过其子类来笼罩某些步骤,从而使得雷同的算法框架能够有不同的执行后果。模板办法提供了一个模板办法来定义算法框架,而某些具体步骤的实现能够在其子类中实现。 1.2 定义模板办法模式:定义一个操作中算法的框架,而将一些步骤提早到子类中,模板办法使得子类能够不扭转一个算法的构造即可重定义该算法的某些步骤。 模板办法模式是一品种行为型模式。 1.3 结构图 1.4 角色AbstractClass(抽象类):抽象类中定义了一系列基本操作,这些操作是具体的也能够是形象的,每一个基本操作对应算法的一个步骤,在子类中能够重定义或实现这些步骤,同时抽象类实现了一个模板办法,定义一个算法的框架ConcreteClass(具体子类):实现父类中的形象根本办法,或者笼罩父类中具体基本操作1.5 模板办法与根本办法1.5.1 模板办法模板办法是在抽象类中定义的,把基本操作办法组合成一个总算法或总行为的办法。模板办法在抽象类中定义,并由子类不加以批改齐全继承。模板办法是一个具体方法,给出了一个顶层逻辑框架,而逻辑的组成步骤在抽象类中能够是具体方法,也能够是形象办法。另外因为模板办法是具体方法,因而形象层只能实现为抽象类而不能是接口。 1.5.2 根本办法根本办法是实现算法的各个步骤,是模板办法的组成部分。根本办法又能够分为三种: 形象办法:形象办法就是在抽象类中申明并由子类实现的办法具体方法:具体方法能够由抽象类实现,或者由子类笼罩实现钩子办法:钩子办法能够由抽象类实现,子类能够加以扩大在模板办法模式中,钩子办法个别有两类: 第一类钩子办法是能够与一些具体步骤挂钩,以实现在不同条件下执行模板办法的不同步骤,这类办法个别返回boolean,办法名个别为isXXX第二类钩子办法是实现体为空的具体方法,子类能够依据须要笼罩或者继承这些钩子办法2 典型实现2.1 步骤定义抽象类:申明模板办法以及根本办法定义模板办法:模板办法是抽象类中的具体方法,依照理论须要将根本办法进行组合定义根本办法:定义形象办法,具体方法以及钩子办法,确定好哪些办法交由抽象类实现,哪些办法交由子类实现以及领有哪些钩子办法定义具体子类:实现抽象类的形象办法,依照须要对钩子办法或者具体方法进行笼罩2.2 抽象类abstract class AbstractClass{ public void templateMethod() { primitiveOperation1(); primitiveOperation2(); if(primitiveOperation3()) System.out.println("合乎钩子办法条件"); else System.out.println("不合乎钩子办法条件"); primitiveOperation4(); } public void primitiveOperation1() { System.out.println("抽象类具体方法"); } //抽象类形象办法 abstract public void primitiveOperation2(); //第一类钩子办法 public boolean primitiveOperation3() { return false; } //第二类钩子办法 public void primitiveOperation4() { }}首先定义了模板办法,作为客户端操作的入口。模板办法中对根本办法进行了组合,这里申明了四个根本办法: 第一个是抽象类的具体方法:这是所有子类都领有的雷同实现的办法,不应该被子类笼罩第二个是抽象类的形象办法:子类须要实现该办法以实现变动第三个是第一类钩子办法:这类钩子办法返回一个boolean,能够用于管制是否执行某个步骤,子类能够通过这类钩子办法对模板办法的执行过程进行限度,比方如果不想执行某个步骤能够永远返回false第四个是第二类钩子办法:这类钩子办法中父类提供一个空实现,子类选择性进行笼罩2.3 具体子类class ConcreteClass extends AbstractClass{ public void primitiveOperation2() { System.out.println("子类具体方法"); } public boolean primitiveOperation3() { return true; // 如果想钩子办法返回false能够不实现该办法 // 因为父类默认返回false // return false; } public void primitiveOperation4() { System.out.println("子类笼罩父类第二类钩子办法"); }}这里子类实现了抽象类的形象办法,同时笼罩了两类钩子办法。 ...

August 5, 2020 · 1 min · jiezi

关于设计模式:设计模式学习笔记二十五模板方法模式

1 概述1.1 引言模板办法模式是构造最简略的行为型设计模型,在其构造中只存在父类与之类之间的继承关系,通过应用模板办法模式,能够将一些简单流程的实现步骤封装在一系列根本办法中,在形象父类提供一个称之为模板办法的办法来定义这些根本办法的执行秩序,而通过其子类来笼罩某些步骤,从而使得雷同的算法框架能够有不同的执行后果。模板办法提供了一个模板办法来定义算法框架,而某些具体步骤的实现能够在其子类中实现。 1.2 定义模板办法模式:定义一个操作中算法的框架,而将一些步骤提早到子类中,模板办法使得子类能够不扭转一个算法的构造即可重定义该算法的某些步骤。 模板办法模式是一品种行为型模式。 1.3 结构图 1.4 角色AbstractClass(抽象类):抽象类中定义了一系列基本操作,这些操作是具体的也能够是形象的,每一个基本操作对应算法的一个步骤,在子类中能够重定义或实现这些步骤,同时抽象类实现了一个模板办法,定义一个算法的框架ConcreteClass(具体子类):实现父类中的形象根本办法,或者笼罩父类中具体基本操作1.5 模板办法与根本办法1.5.1 模板办法模板办法是在抽象类中定义的,把基本操作办法组合成一个总算法或总行为的办法。模板办法在抽象类中定义,并由子类不加以批改齐全继承。模板办法是一个具体方法,给出了一个顶层逻辑框架,而逻辑的组成步骤在抽象类中能够是具体方法,也能够是形象办法。另外因为模板办法是具体方法,因而形象层只能实现为抽象类而不能是接口。 1.5.2 根本办法根本办法是实现算法的各个步骤,是模板办法的组成部分。根本办法又能够分为三种: 形象办法:形象办法就是在抽象类中申明并由子类实现的办法具体方法:具体方法能够由抽象类实现,或者由子类笼罩实现钩子办法:钩子办法能够由抽象类实现,子类能够加以扩大在模板办法模式中,钩子办法个别有两类: 第一类钩子办法是能够与一些具体步骤挂钩,以实现在不同条件下执行模板办法的不同步骤,这类办法个别返回boolean,办法名个别为isXXX第二类钩子办法是实现体为空的具体方法,子类能够依据须要笼罩或者继承这些钩子办法2 典型实现2.1 步骤定义抽象类:申明模板办法以及根本办法定义模板办法:模板办法是抽象类中的具体方法,依照理论须要将根本办法进行组合定义根本办法:定义形象办法,具体方法以及钩子办法,确定好哪些办法交由抽象类实现,哪些办法交由子类实现以及领有哪些钩子办法定义具体子类:实现抽象类的形象办法,依照须要对钩子办法或者具体方法进行笼罩2.2 抽象类abstract class AbstractClass{ public void templateMethod() { primitiveOperation1(); primitiveOperation2(); if(primitiveOperation3()) System.out.println("合乎钩子办法条件"); else System.out.println("不合乎钩子办法条件"); primitiveOperation4(); } public void primitiveOperation1() { System.out.println("抽象类具体方法"); } //抽象类形象办法 abstract public void primitiveOperation2(); //第一类钩子办法 public boolean primitiveOperation3() { return false; } //第二类钩子办法 public void primitiveOperation4() { }}首先定义了模板办法,作为客户端操作的入口。模板办法中对根本办法进行了组合,这里申明了四个根本办法: 第一个是抽象类的具体方法:这是所有子类都领有的雷同实现的办法,不应该被子类笼罩第二个是抽象类的形象办法:子类须要实现该办法以实现变动第三个是第一类钩子办法:这类钩子办法返回一个boolean,能够用于管制是否执行某个步骤,子类能够通过这类钩子办法对模板办法的执行过程进行限度,比方如果不想执行某个步骤能够永远返回false第四个是第二类钩子办法:这类钩子办法中父类提供一个空实现,子类选择性进行笼罩2.3 具体子类class ConcreteClass extends AbstractClass{ public void primitiveOperation2() { System.out.println("子类具体方法"); } public boolean primitiveOperation3() { return true; // 如果想钩子办法返回false能够不实现该办法 // 因为父类默认返回false // return false; } public void primitiveOperation4() { System.out.println("子类笼罩父类第二类钩子办法"); }}这里子类实现了抽象类的形象办法,同时笼罩了两类钩子办法。 ...

August 5, 2020 · 1 min · jiezi

关于设计模式:设计模式学习笔记二十四策略模式

1 概述1.1 引言在外出游览时,很多时候的出行形式都不止一条,通常依据理论状况,比方目的地,估算,游览工夫等确定最适宜的出行形式。在软件开发中,也经常会遇到相似的状况,实现某一个性能有多种路径,每一条路径对应一个算法,这时能够应用一种叫做策略模式的设计模式来进行设计。在策略模式中,能够定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法。 这里每一个封装的算法能够被称之为一种策略,为了保障这些策略在应用时具备一致性,个别会提供一个形象的策略类作为规定的定义,每种具体算法对应于一个具体策略类。 策略模式的次要目标是将算法的定义与应用离开,也就是将算法的行为和环境离开,将算法的定义放在专门的策略类中,每一个策略类封装了一种实现算法,应用算法的环境类针对形象策略类进行编程,合乎DIP(依赖倒转准则)。呈现新算法时只须要定义一个新的具体策略类即可。 1.2 定义策略模式:定义一系列算法类,将每一个算法封装起来,并让他们能够互相替换。 策略模式也叫政策模式,是一种对象行为型模式。 1.3 结构图 1.4 角色Context(环境类):应用算法的角色,解决了某个问题时能够采纳的多种策略,在环境类维持一个形象策略类的援用实例,用于定义所采纳的策略Strategy(形象策略类):为反对的算法申明了形象办法,是所有策略类的父类,能够是抽象类或具体类,也能够是接口,环境类通过形象策略类中申明的办法在运行时调用具体策略类中实现的算法ConcreteStrategy(具体策略类):实现了形象策略类中申明的算法,在运行时,具体策略类将笼罩在环境类中定义的形象策略类对象,应用一种具体的算法实现某个业务解决2 典型实现2.1 步骤定义形象策略类:个别实现为接口,申明形象算法定义具体策略类:实现形象策略类,实现其中的具体算法定义环境类:维持一个对形象策略类的援用,通过setter或构造函数注入具体策略类,调用时通过该形象援用调用相应算法2.2 形象策略类interface AbstarctStrategy{ void algorithm();}这里定义为一个接口,只有一个形象算法办法。 2.3 具体策略类class ConcreteStrategy1 implements AbstarctStrategy{ @Override public void algorithm() { System.out.println("具体策略1"); }}class ConcreteStrategy2 implements AbstarctStrategy{ @Override public void algorithm() { System.out.println("具体策略2"); }}定义两个具体策略类,别离示意不同的算法。 2.4 环境类class Context{ private AbstarctStrategy strategy; public void setStrategy(AbstarctStrategy strategy) { this.strategy = strategy; } public void algorithm() { strategy.algorithm(); }}通过setter注入具体策略类,在调用环境类的办法时通过形象策略类调用其中的具体策略类的算法。 2.5 客户端public static void main(String[] args){ Context context = new Context(); context.setStrategy(new ConcreteStrategy1()); context.algorithm(); context.setStrategy(new ConcreteStrategy2()); context.algorithm();}3 实例设计一个电影票打折零碎,有三种不同的打折形式:学生能够享受8折优惠,10周岁以下儿童能够享受减免10元优惠,VIP能够享受半价优惠,应用策略模式进行设计。设计如下: ...

August 5, 2020 · 1 min · jiezi

关于设计模式:设计模式学习笔记二十四策略模式

1 概述1.1 引言在外出游览时,很多时候的出行形式都不止一条,通常依据理论状况,比方目的地,估算,游览工夫等确定最适宜的出行形式。在软件开发中,也经常会遇到相似的状况,实现某一个性能有多种路径,每一条路径对应一个算法,这时能够应用一种叫做策略模式的设计模式来进行设计。在策略模式中,能够定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法。 这里每一个封装的算法能够被称之为一种策略,为了保障这些策略在应用时具备一致性,个别会提供一个形象的策略类作为规定的定义,每种具体算法对应于一个具体策略类。 策略模式的次要目标是将算法的定义与应用离开,也就是将算法的行为和环境离开,将算法的定义放在专门的策略类中,每一个策略类封装了一种实现算法,应用算法的环境类针对形象策略类进行编程,合乎DIP(依赖倒转准则)。呈现新算法时只须要定义一个新的具体策略类即可。 1.2 定义策略模式:定义一系列算法类,将每一个算法封装起来,并让他们能够互相替换。 策略模式也叫政策模式,是一种对象行为型模式。 1.3 结构图 1.4 角色Context(环境类):应用算法的角色,解决了某个问题时能够采纳的多种策略,在环境类维持一个形象策略类的援用实例,用于定义所采纳的策略Strategy(形象策略类):为反对的算法申明了形象办法,是所有策略类的父类,能够是抽象类或具体类,也能够是接口,环境类通过形象策略类中申明的办法在运行时调用具体策略类中实现的算法ConcreteStrategy(具体策略类):实现了形象策略类中申明的算法,在运行时,具体策略类将笼罩在环境类中定义的形象策略类对象,应用一种具体的算法实现某个业务解决2 典型实现2.1 步骤定义形象策略类:个别实现为接口,申明形象算法定义具体策略类:实现形象策略类,实现其中的具体算法定义环境类:维持一个对形象策略类的援用,通过setter或构造函数注入具体策略类,调用时通过该形象援用调用相应算法2.2 形象策略类interface AbstarctStrategy{ void algorithm();}这里定义为一个接口,只有一个形象算法办法。 2.3 具体策略类class ConcreteStrategy1 implements AbstarctStrategy{ @Override public void algorithm() { System.out.println("具体策略1"); }}class ConcreteStrategy2 implements AbstarctStrategy{ @Override public void algorithm() { System.out.println("具体策略2"); }}定义两个具体策略类,别离示意不同的算法。 2.4 环境类class Context{ private AbstarctStrategy strategy; public void setStrategy(AbstarctStrategy strategy) { this.strategy = strategy; } public void algorithm() { strategy.algorithm(); }}通过setter注入具体策略类,在调用环境类的办法时通过形象策略类调用其中的具体策略类的算法。 2.5 客户端public static void main(String[] args){ Context context = new Context(); context.setStrategy(new ConcreteStrategy1()); context.algorithm(); context.setStrategy(new ConcreteStrategy2()); context.algorithm();}3 实例设计一个电影票打折零碎,有三种不同的打折形式:学生能够享受8折优惠,10周岁以下儿童能够享受减免10元优惠,VIP能够享受半价优惠,应用策略模式进行设计。设计如下: ...

August 5, 2020 · 1 min · jiezi

关于设计模式:设计模式学习笔记二十三状态模式

1 概述1.1 引言状态模式用于解决零碎中简单对象的状态转换以及不同状态下行为的封装问题。当零碎中的某个对象存在多个状态,这些状态之间能够进行转换,而且对象在不同状态下行为不雷同时能够应用状态模式。 状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态能够灵便变动,对于客户端而言,毋庸关怀对象状态的转换以及对象所处的以后状态,无论对于何处状态对象,客户端都能够一致性地解决。 1.2 定义状态模式:容许一个对象在其外部状态扭转时扭转它的行为,对象看起来仿佛是批改了它的类。 状态模式是一种对象行为型模式。 1.3 结构图 1.4 角色Context(环境类):环境类角色又称上下文类,是领有多种状态的对象,环境类的状态存在多样性且在不同状态下对象的行为有所不同。在环境类中保护一个形象状态类State的实例,定义以后状态,实现时将具体状态类注入其中State(形象状态类):申明各种不同状态对应的办法,封装具体状态类的独特办法ConcreteState(具体状态类):形象状态类的子类,实现其中的具体状态行为办法2 典型实现2.1 步骤定义环境类:环境类蕴含一个形象状态成员,能够通过构造方法或者setter注入具体状态,同时蕴含业务办法,该业务办法会调用形象状态类的解决状态办法定义形象状态类:申明状态解决办法,应用环境类作为参数定义具体状态类:实现/继承形象状态类,按理论须要实现其中的状态解决办法2.2 环境类class Context{ private State state = new ConcreteState1(); public void setState(State state) { this.state = state; } public void request() { state.handle(this); }}具备默认初始化状态,能够通过setter批改状态,request为环境类业务办法,其中调用了形象状态类的状态解决办法。 2.3 形象状态类interface State{ void handle(Context context);}这里设计为接口,应用环境类作为参数。 2.4 具体状态类class ConcreteState1 implements State{ @Override public void handle(Context context) { System.out.println("具体状态1办法"); context.setState(new ConcreteState2()); }}class ConcreteState2 implements State{ @Override public void handle(Context context) { System.out.println("具体状态2办法"); context.setState(new ConcreteState1()); }}两个具体状态类,执行完具体状态类外面的代码后,通过环境类参数将环境类切换到另一个状态。 ...

August 5, 2020 · 3 min · jiezi

关于设计模式:设计模式学习笔记二十三状态模式

1 概述1.1 引言状态模式用于解决零碎中简单对象的状态转换以及不同状态下行为的封装问题。当零碎中的某个对象存在多个状态,这些状态之间能够进行转换,而且对象在不同状态下行为不雷同时能够应用状态模式。 状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态能够灵便变动,对于客户端而言,毋庸关怀对象状态的转换以及对象所处的以后状态,无论对于何处状态对象,客户端都能够一致性地解决。 1.2 定义状态模式:容许一个对象在其外部状态扭转时扭转它的行为,对象看起来仿佛是批改了它的类。 状态模式是一种对象行为型模式。 1.3 结构图 1.4 角色Context(环境类):环境类角色又称上下文类,是领有多种状态的对象,环境类的状态存在多样性且在不同状态下对象的行为有所不同。在环境类中保护一个形象状态类State的实例,定义以后状态,实现时将具体状态类注入其中State(形象状态类):申明各种不同状态对应的办法,封装具体状态类的独特办法ConcreteState(具体状态类):形象状态类的子类,实现其中的具体状态行为办法2 典型实现2.1 步骤定义环境类:环境类蕴含一个形象状态成员,能够通过构造方法或者setter注入具体状态,同时蕴含业务办法,该业务办法会调用形象状态类的解决状态办法定义形象状态类:申明状态解决办法,应用环境类作为参数定义具体状态类:实现/继承形象状态类,按理论须要实现其中的状态解决办法2.2 环境类class Context{ private State state = new ConcreteState1(); public void setState(State state) { this.state = state; } public void request() { state.handle(this); }}具备默认初始化状态,能够通过setter批改状态,request为环境类业务办法,其中调用了形象状态类的状态解决办法。 2.3 形象状态类interface State{ void handle(Context context);}这里设计为接口,应用环境类作为参数。 2.4 具体状态类class ConcreteState1 implements State{ @Override public void handle(Context context) { System.out.println("具体状态1办法"); context.setState(new ConcreteState2()); }}class ConcreteState2 implements State{ @Override public void handle(Context context) { System.out.println("具体状态2办法"); context.setState(new ConcreteState1()); }}两个具体状态类,执行完具体状态类外面的代码后,通过环境类参数将环境类切换到另一个状态。 ...

August 5, 2020 · 3 min · jiezi

关于设计模式:设计模式15-职责链模式

1. 简介职责链模式的英文翻译是 Chain Of Responsibility Design Pattern。 在 GoF 的《设计模式》中,它是这么定义的: Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.翻译成中文就是: 将申请的发送和接管解耦,让多个接管对象都有机会解决这个申请。将这些接管对象串成一条链,并沿着这条链传递这个申请,直到链上的某个接管对象可能解决它为止。在职责链模式中,多个处理器(也就是刚刚定义中说的“接管对象”)顺次解决同一个申请。一个申请先通过 A 处理器解决,而后再把申请传递给 B 处理器,B 处理器解决完后再传递给 C 处理器,以此类推,造成一个链条。链条上的每个处理器各自承当各自的解决职责,所以叫作职责链模式。 2. 准则首先,职责链模式如何应答代码的复杂性。首先,职责链模式如何让代码满足开闭准则,进步代码的扩展性。

August 5, 2020 · 1 min · jiezi

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

1 繁多职责准则1.1 定义不要存在多于一个导致类变更的起因。 1.2 名词解释艰深的说,即一个类只负责一项职责。 1.3 场景阐明如果类T负责两个不同的职责:职责P1,职责P2。当因为职责P1需要产生扭转而须要批改类T时,有可能会导致本来运行失常的职责P2性能产生故障。 解决形式:遵循繁多职责准则。别离建设两个类T1、T2,使T1实现职责P1性能,T2实现职责P2性能。这样,当批改类T1时,不会使职责P2产生故障危险;同理,当批改T2时,也不会使职责P1产生故障危险。 1.4 长处能够升高类的复杂度,一个类只负责一项职责,其逻辑必定要比负责多项职责简略的多;进步类的可读性,进步零碎的可维护性变更引起的危险升高,变更是必然的,如果繁多职责准则恪守的好,当批改一个性能时,能够显著升高对其余性能的影响。2 里氏替换准则2.1 定义(1)如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。 (2)所有援用基类的中央必须能通明地应用其子类的对象。 2.2 名词解释里氏替换准则艰深的来讲就是:子类能够扩大父类的性能,但不能扭转父类原有的性能。它蕴含以下4层含意: 子类能够实现父类的形象办法,但不能笼罩父类的非形象办法。子类中能够减少本人特有的办法。当子类的办法重载父类的办法时,办法的前置条件(即办法的形参)要比父类办法的输出参数更宽松。当子类的办法实现父类的形象办法时,办法的后置条件(即办法的返回值)要比父类更严格。2.3 场景阐明有一性能P1,由类A实现。现须要将性能P1进行扩大,扩大后的性能为P,其中P由原有性能P1与新性能P2组成。新性能P由类A的子类B来实现,则子类B在实现新性能P2的同时,有可能会导致原有性能P1产生故障。 解决形式:当应用继承时,遵循里氏替换准则。类B继承类A时,除增加新的办法实现新增性能P2外,尽量不要重写父类A的办法,也尽量不要重载父类A的办法。 3 依赖倒置3.1 定义高层模块不应该依赖低层模块,二者都应该依赖其形象;形象不应该依赖细节;细节应该依赖形象。 3.2 名词解释依赖倒置准则的核心思想是面向接口编程。在理论编程中,个别须要做到如下3点: 低层模块尽量都要有抽象类或接口,或者都有。变量的申明类型尽量是抽象类或接口。应用继承时遵循里氏替换准则。3.3 场景阐明类A间接依赖类B,如果要将类A改为依赖类C,则必须通过批改类A的代码来达成。这种场景下,类A个别是高层模块,负责简单的业务逻辑;类B和类C是低层模块,负责根本的原子操作;如果批改类A,会给程序带来不必要的危险。 解决形式:将类A批改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C产生分割,则会大大降低批改类A的几率。 4 接口隔离准则4.1 定义客户端不应该依赖它不须要的接口;一个类对另一个类的依赖应该建设在最小的接口上。 4.2 名词解释接口隔离准则次要束缚接口,次要针对程序整体框架的形象构建。 采纳接口隔离准则对接口进行束缚时,要留神以下几点: 接口尽量小,然而要有限度。对接口进行细化能够进步程序设计灵活性是不挣的事实,然而如果过小,则会造成接口数量过多,使设计复杂化。所以肯定要适度。为依赖接口的类定制服务,只裸露给调用的类它须要的办法,它不须要的办法则暗藏起来。只有专一地为一个模块提供定制服务,能力建设最小的依赖关系。进步内聚,缩小对外交互。使接口用起码的办法去实现最多的事件。使用接口隔离准则,肯定要适度,接口设计的过大或过小都不好 4.3 场景阐明类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不须要的办法。 解决形式:将臃肿的接口I拆分为独立的几个接口,类A和类C别离与他们须要的接口建设依赖关系。也就是采纳接口隔离准则。 5 迪米特准则5.1 定义一个对象应该对其余对象放弃起码的理解。 5.2 名词解释迪米特法令的初衷是升高类之间的耦合,因为每个类都缩小了不必要的依赖,因而确实能够升高耦合关系。然而凡事都有度,尽管能够防止与非间接的类通信,然而要通信,必然会通过一个“中介”来产生分割,过分的应用迪米特准则,会产生大量这样的中介和传递类,导致系统复杂度变大。所以在采纳迪米特法令时要重复衡量,既做到构造清晰,又要高内聚低耦合。 5.3 场景阐明类与类之间的关系越亲密,耦合度越大,当一个类产生扭转时,对另一个类的影响也越大。 解决形式:尽量升高类与类之间的耦合。 6 开闭准则6.1 定义一个软件实体如类、模块和函数应该对扩大凋谢,对批改敞开。 6.2 名词解释用形象构建框架,用实现扩大细节。因为形象灵活性好,适应性广,只有形象的正当,能够根本放弃软件架构的稳固。而软件中易变的细节,用从抽象派生的实现类来进行扩大,当软件须要发生变化时,只须要依据需要从新派生一个实现类来扩大就能够了。当然前提是形象要正当,要对需要的变更有前瞻性和预见性。 ...

August 2, 2020 · 1 min · jiezi

关于设计模式:设计模式学习笔记十九迭代器模式

1 概述1.1 引言在软件开发中,有一些类能够存储多个成员对象(元素),这些类通常称为聚合类,对应的对象称为聚合对象。聚合对象领有两个职责,一个是存储数据,一个是遍历数据,前者是聚合对象的根本职责,后者是能够变动以及拆散的,因而,能够将遍历数据的行为从聚合对象中分离出来,封装在一个被称之为“迭代器”的对象中,又迭代器来提供遍历聚合对象外部数据的行为。 1.2 定义迭代器模式:提供一种办法来拜访对象,而不必裸露这个对象的外部示意,别名叫游标。 迭代器模式是一种对象行为型模式。 1.3 结构图 1.4 角色Iterator(形象迭代器):定义了拜访和遍历元素的接口,申明了用于遍历数据元素的办法,比方first(获取第一个元素),next(获取下一个元素),hasNext(判断是否有下一个元素),currentItem(获取以后元素)ConcreteIterator(具体迭代器):实现了形象迭代器,实现对聚合对象的遍历,同时在具体迭代器中通过游标来记录聚合对象中所处的以后地位,通常游标是一个非负整数Aggregate(形象聚合类):用于存储和治理元素对象,申明一个createIterator办法创立一个迭代器对象,充当形象迭代器的工厂角色ConcreteAggregate(具体聚合类):实现了形象聚合类中的createIterator办法,返回一个具体迭代器实例2 典型实现2.1 步骤定义形象迭代器:个别为接口,申明具体迭代器的办法定义形象聚合类:个别为接口,蕴含治理聚合元素的办法以及创立形象迭代器的办法定义具体聚合类:外部创立汇合存储聚合元素,在创立迭代器办法中将汇合作为构造方法参数注入到具体迭代器中并返回该具体迭代器定义具体迭代器类:实现形象迭代器的办法,个别蕴含一个来自具体聚合类的汇合援用以及一个示意元素地位的整型的游标2.2 形象迭代器interface Iterator{ String first(); String next(); boolean hasNext(); String currentItem();}2.3 形象聚合类interface Aggregate{ Iterator createIterator(); void add(String s);}创立迭代器通过createIterator,add用于削减元素。 2.4 具体聚合类class ConcreteAggregate implements Aggregate{ List<String> list = new ArrayList<>(); @Override public Iterator createIterator() { return new ConcreteIterator(list); } @Override public void add(String s) { list.add(s); }}在创立迭代器办法中,通过构造方法把汇合对象注入到具体迭代器中。 2.5 具体迭代器class ConcreteIterator implements Iterator{ private int cursor; private List<String> list; public ConcreteIterator(List<String> list) { this.list = list; this.cursor = -1; } @Override public String first() { return list.size() > 0 ? list.get(cursor = 0) : null; } @Override public String next() { return list.get( cursor + 1 < list.size() ? ++cursor : cursor ); } @Override public boolean hasNext() { return cursor+1 < list.size(); } @Override public String currentItem() { return list.get(cursor); }}具体迭代器中蕴含了一个游标,用于记录以后拜访的地位。构造方法中将游标初始化为-1而不是初始化为0,这样第一次应用next时便会拜访第一个元素。 ...

August 2, 2020 · 4 min · jiezi

关于设计模式:设计模式学习笔记十八解释器模式

1 概述1.1 引言解释器模式是一种应用频率较低然而学习难度较大的设计模式,用于形容如何应用面向对象语言形成一个简略的语言解释器。某些状况下可能须要自定义一个新语言,这种语言具备本人的文法规定,这时能够应用解释器模式进行设计,比方模仿机器人的控制程序,每一条指令对应一个动作,通过解释输出的指令来实现对机器人的管制。上面先来看一些术语定义。 1.2 相干术语1.2.1 文法规定文法规定是用于描述语言的语法的规定,比方,汉语中一个句子的文法规定为: 主 谓 宾这就是句子的文法规定,同样计算机语言也有本人的文法规定。 1.2.2 BNF符号BNF是Backus-Naur Form的缩写,是由John Backus以及Peter Naur首次引入的一种形式化符号来形容给定语言的语法,BNF中定义的局部符号如下: ::=:示意定义为,右边的语言单位能够通过左边进行阐明和定义|:示意或者"或':双引号或单引号外面的字符串示意字符串自身1.2.3 终结符与非终结符在以下的模仿形容机器人挪动的文法规定中: expression ::= direction action distance | composite //表达式composite ::= expression 'and' expression //复合表达式direction ::= 'up' | 'down' | 'left'| 'right' //挪动方向action ::= 'move' | 'run' //挪动形式distance ::= an integer //挪动间隔定义了5条文法规则,对应5个语言单位,这些语言单位能够分为: 终结符(也叫终结符表达式):语言的最小组成单位,不能再拆分,比方下面的direction或action非终结符(也叫非终结符表达式):一个残缺的句子,蕴含一些列终结符或非终结符1.2.4 形象语法树除了应用文法规定定义一个语言外,还能应用一种叫形象语法树的直观形式示意,例如表达式: 1 / 2 * 3 - 4 + 1能够通过如下形象语法树定义:在该形象语法树中,能够通过终结符value以及非终结符operation组成简单的语句,终结符作为形象语法树的叶子,非终结符作为非叶子节点,能够将终结符或者蕴含终结符与非终结符的节点作为子节点。 1.3 定义解释器模式:定义一个语言的文法,并且建设一个解释器来解释该语言中的句子。 这里的语言指的是应用规定格局以及语法的代码。解释器模式是一品种行为型模式。 1.4 结构图 1.5 角色AbstractExpression(形象表达式):申明了形象的解释操作,是所有终结符表达式以及非终结符表达式的父类TerminalExpression(终结符表达式):形象表达式的子类,实现了与文法规定中的终结符相关联的解释操作,句子中的每一个终结符都是该类的一个实例,通常只有少数几个终结符表达式类NonterminalExpression(非终结符表达式):也是形象表达式的子类,实现了文法规定中非终结符的解释操作,因为非终结符表达式能够蕴含非终结符表达式以及终结符表达式,因而个别通过递归形式实现解释Context(环境类):用于存储解释器之外的一些全局信息,通常它长期存储须要解释的语句2 典型实现2.1 步骤(可选)定义环境类:首先对环境类进行定义,应用汇合存储相干的全局或公共信息,用于在具体解释时获取,如果毋庸全局信息则环境类能够省略定义形象表达式类:接口/抽象类,申明形象解释操作定义终结符表达式类:继承/实现形象表达式,定义终结符的解释操作定义非终结符表达式类:继承/实现形象表达式,定义非终结符解释操作,个别通过递归解决2.2 环境类这里临时不须要环境类,为了兼容定义一个空类: ...

August 2, 2020 · 2 min · jiezi

关于设计模式:设计模式学习笔记十八解释器模式

1 概述1.1 引言解释器模式是一种应用频率较低然而学习难度较大的设计模式,用于形容如何应用面向对象语言形成一个简略的语言解释器。某些状况下可能须要自定义一个新语言,这种语言具备本人的文法规定,这时能够应用解释器模式进行设计,比方模仿机器人的控制程序,每一条指令对应一个动作,通过解释输出的指令来实现对机器人的管制。上面先来看一些术语定义。 1.2 相干术语1.2.1 文法规定文法规定是用于描述语言的语法的规定,比方,汉语中一个句子的文法规定为: 主 谓 宾这就是句子的文法规定,同样计算机语言也有本人的文法规定。 1.2.2 BNF符号BNF是Backus-Naur Form的缩写,是由John Backus以及Peter Naur首次引入的一种形式化符号来形容给定语言的语法,BNF中定义的局部符号如下: ::=:示意定义为,右边的语言单位能够通过左边进行阐明和定义|:示意或者"或':双引号或单引号外面的字符串示意字符串自身1.2.3 终结符与非终结符在以下的模仿形容机器人挪动的文法规定中: expression ::= direction action distance | composite //表达式composite ::= expression 'and' expression //复合表达式direction ::= 'up' | 'down' | 'left'| 'right' //挪动方向action ::= 'move' | 'run' //挪动形式distance ::= an integer //挪动间隔定义了5条文法规则,对应5个语言单位,这些语言单位能够分为: 终结符(也叫终结符表达式):语言的最小组成单位,不能再拆分,比方下面的direction或action非终结符(也叫非终结符表达式):一个残缺的句子,蕴含一些列终结符或非终结符1.2.4 形象语法树除了应用文法规定定义一个语言外,还能应用一种叫形象语法树的直观形式示意,例如表达式: 1 / 2 * 3 - 4 + 1能够通过如下形象语法树定义:在该形象语法树中,能够通过终结符value以及非终结符operation组成简单的语句,终结符作为形象语法树的叶子,非终结符作为非叶子节点,能够将终结符或者蕴含终结符与非终结符的节点作为子节点。 1.3 定义解释器模式:定义一个语言的文法,并且建设一个解释器来解释该语言中的句子。 这里的语言指的是应用规定格局以及语法的代码。解释器模式是一品种行为型模式。 1.4 结构图 1.5 角色AbstractExpression(形象表达式):申明了形象的解释操作,是所有终结符表达式以及非终结符表达式的父类TerminalExpression(终结符表达式):形象表达式的子类,实现了与文法规定中的终结符相关联的解释操作,句子中的每一个终结符都是该类的一个实例,通常只有少数几个终结符表达式类NonterminalExpression(非终结符表达式):也是形象表达式的子类,实现了文法规定中非终结符的解释操作,因为非终结符表达式能够蕴含非终结符表达式以及终结符表达式,因而个别通过递归形式实现解释Context(环境类):用于存储解释器之外的一些全局信息,通常它长期存储须要解释的语句2 典型实现2.1 步骤(可选)定义环境类:首先对环境类进行定义,应用汇合存储相干的全局或公共信息,用于在具体解释时获取,如果毋庸全局信息则环境类能够省略定义形象表达式类:接口/抽象类,申明形象解释操作定义终结符表达式类:继承/实现形象表达式,定义终结符的解释操作定义非终结符表达式类:继承/实现形象表达式,定义非终结符解释操作,个别通过递归解决2.2 环境类这里临时不须要环境类,为了兼容定义一个空类: ...

August 2, 2020 · 2 min · jiezi

关于设计模式:设计模式学习笔记十七命令模式

1 概述1.1 引言日常生活中,能够通过开关管制一些电器的开启和敞开,比方电灯和排气扇。能够将开关了解成一个申请发送者,电灯是申请的最红接收者以及解决者,开关与电灯之间不存在间接的耦合关系,两者通过电线连贯在一起,使不同的电线能够连贯不同的申请接收者,只须要更换一根电线,雷同的发送者(开关)既可对应不同的接收者(电器)。 软件开发中常常须要向某些对象发送申请,然而并不知道具体的接收者是谁,也不晓得被申请的操作是哪个,此时心愿以一种松耦合的形式来设计软件,使得申请发送者与申请接收者之间可能打消彼此之间的耦合,让对象之间的调用关系更加灵便,能够灵便地指定申请接收者以及被申请的操作,此时能够应用命令模式进行设计。 命令模式能够将申请发送者和接收者齐全解耦,发送者与接收者之间没有间接援用关系,发送申请的对象只须要晓得如何发送申请,而不用晓得如何实现申请。 1.2 定义命令模式:将一个申请封装成一个对象,从而可用不同的申请对客户进行参数化,对申请排队或者记录申请日志,以及反对可撤销的操作。 命令模式是一种对象行为型模式,别名为动作模式或者事务模式。 1.3 结构图 1.4 角色Command(形象命令类):形象命令类个别是一个抽象类或者接口,在其中申明了用于执行申请的execute()办法,通过这些办法能够调用申请接收者的相干操作ConcreteCommand(具体命令类):实现了形象命令类中申明的办法,对应具体的接收者对象,将接收者对象的动作绑定其中,在实现execute()办法时,将调用接收者对象的相干操作Invoker(调用者):调用者即申请发送者,通过命令对象来执行申请。一个调用者并不需要设计时确定接收者,因而它只与形象命令类之间存在关联关系。程序运行时将具体命令对象注入,并调用其中的execute()办法,从而实现间接调用申请接收者的相干操作Receiver(接收者):接收者执行与申请相干的操作,具体实现对申请的业务解决2 典型实现2.1 步骤定义形象命令类:定义执行申请的办法定义调用者:在调用办法外面蕴含对具体命令的调用,同时须要蕴含一个对形象命令的援用定义接收者:定义接管申请的业务办法定义具体命令类:继承/实现形象命令类,实现其中执行申请办法,转发到接收者的接管办法2.2 形象命令类这里实现为一个接口: interface Command{ void execute();}2.3 调用者class Invoker{ private Command command; public Invoker(Command command) { this.command = command; } public void call() { System.out.println("调用者操作"); command.execute(); }}调用者能够通过构造方法或者setter注入具体命令,对外提供一个调用办法call,当调用此办法时调用具体命令的execute。 2.4 接收者class Receiver{ public void action() { System.out.println("接收者操作"); }}这里的接收者只有一个action,示意接管办法。 2.5 具体命令类class ConcreteCommand implements Command{ private Receiver receiver = new Receiver(); @Override public void execute() { receiver.action(); }}具体命令类中须要蕴含一个对接收者的援用,以便在execute中调用接收者。 ...

August 2, 2020 · 3 min · jiezi

关于设计模式:设计模式学习笔记十七命令模式

1 概述1.1 引言日常生活中,能够通过开关管制一些电器的开启和敞开,比方电灯和排气扇。能够将开关了解成一个申请发送者,电灯是申请的最红接收者以及解决者,开关与电灯之间不存在间接的耦合关系,两者通过电线连贯在一起,使不同的电线能够连贯不同的申请接收者,只须要更换一根电线,雷同的发送者(开关)既可对应不同的接收者(电器)。 软件开发中常常须要向某些对象发送申请,然而并不知道具体的接收者是谁,也不晓得被申请的操作是哪个,此时心愿以一种松耦合的形式来设计软件,使得申请发送者与申请接收者之间可能打消彼此之间的耦合,让对象之间的调用关系更加灵便,能够灵便地指定申请接收者以及被申请的操作,此时能够应用命令模式进行设计。 命令模式能够将申请发送者和接收者齐全解耦,发送者与接收者之间没有间接援用关系,发送申请的对象只须要晓得如何发送申请,而不用晓得如何实现申请。 1.2 定义命令模式:将一个申请封装成一个对象,从而可用不同的申请对客户进行参数化,对申请排队或者记录申请日志,以及反对可撤销的操作。 命令模式是一种对象行为型模式,别名为动作模式或者事务模式。 1.3 结构图 1.4 角色Command(形象命令类):形象命令类个别是一个抽象类或者接口,在其中申明了用于执行申请的execute()办法,通过这些办法能够调用申请接收者的相干操作ConcreteCommand(具体命令类):实现了形象命令类中申明的办法,对应具体的接收者对象,将接收者对象的动作绑定其中,在实现execute()办法时,将调用接收者对象的相干操作Invoker(调用者):调用者即申请发送者,通过命令对象来执行申请。一个调用者并不需要设计时确定接收者,因而它只与形象命令类之间存在关联关系。程序运行时将具体命令对象注入,并调用其中的execute()办法,从而实现间接调用申请接收者的相干操作Receiver(接收者):接收者执行与申请相干的操作,具体实现对申请的业务解决2 典型实现2.1 步骤定义形象命令类:定义执行申请的办法定义调用者:在调用办法外面蕴含对具体命令的调用,同时须要蕴含一个对形象命令的援用定义接收者:定义接管申请的业务办法定义具体命令类:继承/实现形象命令类,实现其中执行申请办法,转发到接收者的接管办法2.2 形象命令类这里实现为一个接口: interface Command{ void execute();}2.3 调用者class Invoker{ private Command command; public Invoker(Command command) { this.command = command; } public void call() { System.out.println("调用者操作"); command.execute(); }}调用者能够通过构造方法或者setter注入具体命令,对外提供一个调用办法call,当调用此办法时调用具体命令的execute。 2.4 接收者class Receiver{ public void action() { System.out.println("接收者操作"); }}这里的接收者只有一个action,示意接管办法。 2.5 具体命令类class ConcreteCommand implements Command{ private Receiver receiver = new Receiver(); @Override public void execute() { receiver.action(); }}具体命令类中须要蕴含一个对接收者的援用,以便在execute中调用接收者。 ...

August 2, 2020 · 3 min · jiezi

关于设计模式:设计模式学习笔记十六职责链模式

1 概述1.1 引言很多状况下,一个软件系统中能够解决某个申请的对象不知一个,比方洽购单的审批,主任,副董事长,董事长,董事会都能够解决洽购单,他们能够形成一条解决洽购单的链式构造,洽购单沿着这条链进行传递,这条链就叫职责链。 职责链能够是一条直线,一个环或者一个树形构造,最常见的职责链是直线型,即沿着一条单向的链来传递申请。链上的每一个对象都是申请解决者,职责链模式能够将申请的解决者组织成一条链,并让申请沿着链传递,由链上的解决者对申请进行解决,客户端毋庸关系申请的解决细节以及具体的传递,只须要将申请发送到链上即可,实现申请发送者以及申请解决者的解耦。 1.2 定义职责链模式:防止将申请发送者与接收者耦合在一起,让多个对象都有机会接管申请,将这些对象连接成一条链,并且沿着这条链传递申请,直到有对象解决它为止。 职责链模式是一种行为型模式。 1.3 结构图 1.4 角色Handler(形象解决者):定义一个解决申请的接口,个别为抽象类。因为每一个解决者的下家还是一个解决者,因而在形象解决者中定义了一个形象解决者的对象作为对下一个解决者的援用,通过该援用,解决者能够连成一条链ConcreteHandler(具体解决者):形象解决者的子类,实现具体解决办法,在解决前须要判断是否具备解决权限,如果领有权限则解决,没有则转发到下一个解决者2 典型实现2.1 步骤定义形象解决者:定义解决申请接口以及定义一个形象解决者成员,作为下一个解决者的援用,个别为了让具体解决者不便调用,定义为protected定义具体解决者:解决/转发申请,解决申请前先判断是否具备权限 ,领有则解决申请,否则转发申请客户端创立职责链:职责链模式并不创立职责链,职责链交由客户端创立,依据理论须要定义职责链程序2.2 形象解决者abstract class Handler{ protected Handler successor; public void setSuccessor(Handler successor) { this.successor = successor; } public abstract void handleRequest(int num);}领有一个设置下一解决者的对象,能够通过setter注入,同时申明形象解决办法。 2.3 具体解决者class ConcreteHandler1 extends Handler{ @Override public void handleRequest(int num) { if(num < 10) { System.out.println("解决小于10的数字:"+num); } else successor.handleRequest(num); }}class ConcreteHandler2 extends Handler{ @Override public void handleRequest(int num) { if(num < 20) { System.out.println("解决大于等于10且小于20的数字:"+num); } else successor.handleRequest(num); }}class ConcreteHandler3 extends Handler{ @Override public void handleRequest(int num) { if(num < 30) { System.out.println("解决大于等于20且小于30的数字:"+num); } else successor.handleRequest(num); }}继承形象解决者,首先判断是否领有权限解决(这里是一个简略的if判断),如果有就解决,没有的话通过protected对象,也就是转发给下一个解决者解决。 ...

July 31, 2020 · 2 min · jiezi

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

如何防止简短的if-else/switch分支判断代码? 1. 简介策略模式,英文全称是 Strategy Design Pattern。在 GoF 的《设计模式》一书中,它是这样定义的: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.翻译成中文就是:定义一族算法类,将每个算法别离封装起来,让它们能够相互替换。策略模式能够使算法的变动独立于应用它们的客户端(这里的客户端代指应用算法的代码)。 工厂模式是解耦对象的创立和应用,观察者模式是解耦观察者和被观察者。策略模式跟两者相似,也能起到解耦的作用,不过,它解耦的是策略的定义、创立、应用这三局部。

July 30, 2020 · 1 min · jiezi

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

如何防止简短的if-else/switch分支判断代码? 1. 简介策略模式,英文全称是 Strategy Design Pattern。在 GoF 的《设计模式》一书中,它是这样定义的: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.翻译成中文就是:定义一族算法类,将每个算法别离封装起来,让它们能够相互替换。策略模式能够使算法的变动独立于应用它们的客户端(这里的客户端代指应用算法的代码)。 工厂模式是解耦对象的创立和应用,观察者模式是解耦观察者和被观察者。策略模式跟两者相似,也能起到解耦的作用,不过,它解耦的是策略的定义、创立、应用这三局部。

July 30, 2020 · 1 min · jiezi

关于设计模式:设计模式13-模板模式

1. 简介模板模式次要是用来解决 复用和扩大 两个问题。 模板模式,全称是模板办法设计模式,英文是 Template Method Design Pattern。 在 GoF 的《设计模式》一书中,它是这么定义的:Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.翻译成中文就是: 模板办法模式在一个办法中定义一个算法骨架,并将某些步骤推延到子类中实现。模板办法模式能够让子类在不扭转算法整体构造的状况下,从新定义算法中的某些步骤。这里的“算法”,咱们能够了解为狭义上的“业务逻辑”,并不特指数据结构和算法中的“算法”。这里的算法骨架就是“模板”,蕴含算法骨架的办法就是“模板办法”,这也是模板办法模式名字的由来。 复用和扩大。 2. 复用3. 扩大这里所说的扩大,并不是指代码的扩展性,而是指框架的扩展性.基于这个作用,模板模式罕用在框架的开发中,让框架用户能够在不批改框架源码的状况下,定制化框架的性能。

July 30, 2020 · 1 min · jiezi

关于设计模式:设计模式13-模板模式

1. 简介模板模式次要是用来解决 复用和扩大 两个问题。 模板模式,全称是模板办法设计模式,英文是 Template Method Design Pattern。 在 GoF 的《设计模式》一书中,它是这么定义的:Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.翻译成中文就是: 模板办法模式在一个办法中定义一个算法骨架,并将某些步骤推延到子类中实现。模板办法模式能够让子类在不扭转算法整体构造的状况下,从新定义算法中的某些步骤。这里的“算法”,咱们能够了解为狭义上的“业务逻辑”,并不特指数据结构和算法中的“算法”。这里的算法骨架就是“模板”,蕴含算法骨架的办法就是“模板办法”,这也是模板办法模式名字的由来。 复用和扩大。 2. 复用3. 扩大这里所说的扩大,并不是指代码的扩展性,而是指框架的扩展性.基于这个作用,模板模式罕用在框架的开发中,让框架用户能够在不批改框架源码的状况下,定制化框架的性能。

July 30, 2020 · 1 min · jiezi

关于设计模式:设计模式12-观察者模式

1. 简介观察者模式(Observer Design Pattern)也被称为公布订阅模式(Publish-Subscribe Design Pattern)。 在 GoF 的《设计模式》一书中,它的定义是这样的: Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.翻译成中文就是:在对象之间定义一个一对多的依赖,当一个对象状态扭转的时候,所有依赖的对象都会主动收到告诉。 个别状况下,被依赖的对象叫作被观察者(Observable),依赖的对象叫作观察者(Observer)。不过,在理论的我的项目开发中,这两种对象的称说是比拟灵便的,有各种不同的叫法,比方:Subject-Observer、Publisher-Subscriber、Producer-Consumer、EventEmitter-EventListener、Dispatcher-Listener。不管怎么称说,只有利用场景合乎刚刚给出的定义,都能够看作观察者模式。

July 30, 2020 · 1 min · jiezi

关于设计模式:设计模式11-享元模式

1. 享元模式简要介绍所谓“享元”,顾名思义就是被共享的单元。享元模式的用意是复用对象,节俭内存,前提是享元对象是不可变对象。 具体来讲,当一个零碎中存在大量反复对象的时候,如果这些反复的对象是不可变对象,咱们就能够利用享元模式将对象设计成享元,在内存中只保留一份实例,供多处代码援用。这样能够缩小内存中对象的数量,起到节俭内存的目标。 实际上,不仅仅雷同对象能够设计成享元,对于类似对象,咱们也能够将这些对象中雷同的局部(字段)提取进去,设计成享元,让这些大量类似对象援用这些享元。 这里我略微解释一下,定义中的“不可变对象”指的是,一旦通过构造函数初始化实现之后,它的状态(对象的成员变量或者属性)就不会再被批改了。所以,不可变对象不能裸露任何 set() 等批改外部状态的办法。之所以要求享元是不可变对象,那是因为它会被多处代码共享应用,防止一处代码对享元进行了批改,影响到其余应用它的代码。

July 30, 2020 · 1 min · jiezi

关于设计模式:设计模式11-享元模式

1. 享元模式简要介绍所谓“享元”,顾名思义就是被共享的单元。享元模式的用意是复用对象,节俭内存,前提是享元对象是不可变对象。 具体来讲,当一个零碎中存在大量反复对象的时候,如果这些反复的对象是不可变对象,咱们就能够利用享元模式将对象设计成享元,在内存中只保留一份实例,供多处代码援用。这样能够缩小内存中对象的数量,起到节俭内存的目标。 实际上,不仅仅雷同对象能够设计成享元,对于类似对象,咱们也能够将这些对象中雷同的局部(字段)提取进去,设计成享元,让这些大量类似对象援用这些享元。 这里我略微解释一下,定义中的“不可变对象”指的是,一旦通过构造函数初始化实现之后,它的状态(对象的成员变量或者属性)就不会再被批改了。所以,不可变对象不能裸露任何 set() 等批改外部状态的办法。之所以要求享元是不可变对象,那是因为它会被多处代码共享应用,防止一处代码对享元进行了批改,影响到其余应用它的代码。

July 30, 2020 · 1 min · jiezi

关于设计模式:设计模式学习笔记十四享元模式

1 概述1.1 引言当一个零碎中运行时的产生的对象太多,会带来性能降落等问题,比方一个文本字符串存在大量反复字符,如果每一个字符都用一个独自的对象示意,将会占用较多内存空间。 那么该如何避免出现大量雷同或类似的对象,同时又不影响客户端以面向对象的形式操作呢? 享元模式正为解决这一问题而生,通过共享技术实现雷同或类似对象的重用,在逻辑上每一个呈现的字符都有一个对象与之对应,然而物理上却共享一个享元对象。 在享元模式中,存储共享实例的中央称为享元池,能够针对每一个不同的字符创立一个享元对象,搁置于享元池中,须要时取出,示意图如下: 1.2 外部状态与内部状态享元模式以共享的形式高效地反对大量细粒度对象的重用,能做到共享的要害是辨别了外部状态以及内部状态。 外部状态:存储在享元对象外部并且不会随环境扭转而扭转,外部状态能够共享,例如字符的内容,字符a永远是字符a,不会变为字符b内部状态:可能随环境扭转而扭转,不能够共享的状态,通常由客户端保留,并在享元对象被创立之后,须要应用的时候再传入到享元对象外部。内部状态之间通常是互相独立的,比方字符的色彩,字号,字体等,能够独立变动,没有影响,客户端在应用时将内部状态注入到享元对象中正因为辨别了外部状态以及内部状态,能够将具备雷同外部状态的对象存储在享元池中,享元池的对象是能够实现共享的,须要的时候从中取出,实现对象的复用。通过向取出的对象注入不同的内部状态,能够失去一系列类似的对象,而这些对象实际上只存储一份。 1.3 定义享元模式:使用共享技术无效地反对大量细粒度对象的复用。 零碎只应用大量的对象,而这些对象都很类似,状态变动很小,能够实现对象的屡次复用。因为享元模式要求可能共享的对象必须是细粒度对象,因而又叫轻量级模式,是一种对象结构型模式。 1.4 结构图享元模式个别联合工厂模式一起应用,结构图如下: 1.5 角色Flyweights(形象享元类):通常是一个接口或者抽象类,在形象享元类中申明了具体享元类公共的办法,这些办法能够向外界提供享元对象的外部数据(外部状态),同时也能够通过这些办法来设置内部数据(内部状态)ConcreteFlyweight(具体享元类):实现/继承形象共享类,实例称为共享对象,在具体享元类中为外部状态提供了存储空间,通常能够联合单例模式来设计具体享元类UnsharedConcreteFlyweight(非共享具体享元类):并不是所有的形象享元子类都须要被共享,不能被共享的子类可设计为非共享具体享元类,当须要一个非具体享元对象时能够间接实例化创立FlyweightFactory(享元工厂类):享元工厂类用于创立并治理享元对象,针对形象享元类编程,将具体享元对象存储于享元池中。个别应用键值对汇合(比方Java中的HashMap)作为享元池,当客户端获取享元对象时,首先判断是否存在,存在则从汇合中取出并返回,不存在则创立新具体享元的实例,存储于享元池中并返回新实例2 典型实现2.1 步骤定义形象享元类:将形象享元类定义为接口或者抽象类,申明业务办法定义具体享元类:继承或实现形象享元,实现其中的业务办法,同时应用单例模式设计,确保每个具体享元类提供惟一的享元对象(可选)定义非共享具体享元类:继承或实现形象享元类,不应用单例模式设计,每次客户端获取都会返回一个新实例定义享元工厂类:通常应用一个键值对汇合作为享元池,依据键值返回对应的具体享元对象或非共享具体享元对象2.2 形象享元类这里应用接口实现,蕴含一个opeartion业务办法: interface Flyweight{ void operation(String extrinsicState);}2.3 具体享元类简略设计两个枚举单例的具体享元类: enum ConcreteFlyweight1 implements Flyweight{ INSTANCE("INTRINSIC STATE 1"); private String intrinsicState; private ConcreteFlyweight1(String intrinsicState) { this.intrinsicState = intrinsicState; } @Override public void operation(String extrinsicState) { System.out.println("具体享元操作"); System.out.println("外部状态:"+intrinsicState); System.out.println("内部状态:"+extrinsicState); }}enum ConcreteFlyweight2 implements Flyweight{ INSTANCE("INTRINSIC STATE 2"); private String intrinsicState; private ConcreteFlyweight2(String intrinsicState) { this.intrinsicState = intrinsicState; } @Override public void operation(String extrinsicState) { System.out.println("具体享元操作"); System.out.println("外部状态:"+intrinsicState); System.out.println("内部状态:"+extrinsicState); }}2.4 非共享具体享元类两个简略的非共享具体享元类,不是枚举单例类: ...

July 27, 2020 · 4 min · jiezi

关于设计模式:从发布订阅模式入手读懂Nodejs的EventEmitter源码

后面一篇文章setTimeout和setImmediate到底谁先执行,本文让你彻底了解Event Loop具体解说了浏览器和Node.js的异步API及其底层原理Event Loop。本文会讲一下不必原生API怎么达到异步的成果,也就是公布订阅模式。公布订阅模式在面试中也是高频考点,本文会本人实现一个公布订阅模式,弄懂了他的原理后,咱们就能够去读Node.js的EventEmitter源码,这也是一个典型的公布订阅模式。 本文所有例子曾经上传到GitHub,同一个repo上面还有我所有博文和例子: https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/DesignPatterns/PubSub 为什么要用公布订阅模式在没有Promise之前,咱们应用异步API的时候常常会应用回调,然而如果有几个相互依赖的异步API调用,回调层级太多可能就会陷入“回调天堂”。上面代码演示了如果咱们有三个网络申请,第二个必须等第一个完结能力收回,第三个必须等第二个完结能力发动,如果咱们应用回调就会变成这样: const request = require("request");request('https://www.baidu.com', function (error, response) { if (!error && response.statusCode == 200) { console.log('get times 1'); request('https://www.baidu.com', function(error, response) { if (!error && response.statusCode == 200) { console.log('get times 2'); request('https://www.baidu.com', function(error, response) { if (!error && response.statusCode == 200) { console.log('get times 3'); } }) } }) }});因为浏览器端ajax会有跨域问题,上述例子我是用Node.js运行的。这个例子外面有三层回调,咱们曾经有点晕了,如果再多几层,那真的就是“天堂”了。 公布订阅模式公布订阅模式是一种设计模式,并不仅仅用于JS中,这种模式能够帮忙咱们解开“回调天堂”。他的流程如下图所示: 音讯核心:负责存储音讯与订阅者的对应关系,有音讯触发时,负责告诉订阅者订阅者:去音讯核心订阅本人感兴趣的音讯发布者:满足条件时,通过音讯核心公布音讯有了这种模式,后面解决几个相互依赖的异步API就不必陷入"回调天堂"了,只须要让前面的订阅后面的胜利音讯,后面的胜利后公布音讯就行了。 本人实现一个公布订阅模式晓得了原理,咱们本人来实现一个公布订阅模式,这次咱们应用ES6的class来实现,如果你对JS的面向对象或者ES6的class还不相熟,请看这篇文章: class PubSub { constructor() { // 一个对象寄存所有的音讯订阅 // 每个音讯对应一个数组,数组构造如下 // { // "event1": [cb1, cb2] // } this.events = {} } subscribe(event, callback) { if(this.events[event]) { // 如果有人订阅过了,这个键曾经存在,就往里面加就好了 this.events[event].push(callback); } else { // 没人订阅过,就建一个数组,回调放进去 this.events[event] = [callback] } } publish(event, ...args) { // 取出所有订阅者的回调执行 const subscribedEvents = this.events[event]; if(subscribedEvents && subscribedEvents.length) { subscribedEvents.forEach(callback => { callback.call(this, ...args); }); } } unsubscribe(event, callback) { // 删除某个订阅,保留其余订阅 const subscribedEvents = this.events[event]; if(subscribedEvents && subscribedEvents.length) { this.events[event] = this.events[event].filter(cb => cb !== callback) } }}解决回调天堂有了咱们本人的PubSub,咱们就能够用它来解决后面的回调天堂问题了: ...

July 27, 2020 · 2 min · jiezi

关于设计模式:设计模式学习笔记十三外观模式

1 概述1.1 引言依据繁多权责准则,软件中将一个零碎划分为若干个子系统有利于升高整个零碎的复杂性,使客户类与子系统之间的通信和相互依赖关系达到最小,办法之一就是引入一个外观角色,为子系统的拜访提供一个简略而繁多的入口。外观模式通过引入一个新的外观角色来升高原有零碎的复杂度,同时升高客户类与子系统类的耦合度。 (这里的子系统是狭义的概念,能够是一个类,一个功能模块,零碎的一个组成部分或者一个残缺的零碎) 如果没有外观角色,每个客户端可能须要和多个子系统之间进行简单的交互,零碎的耦合度很大,简化示意图如下: 而引入外观角色后,客户端只需间接与外观角色交互,客户端与子系统之间的原有复杂度由外观角色实现,从而升高零碎耦合度,简化示意图如下:外观模式要求一个子系统的内部与其外部的通信通过一个对立的外观角色进行,外观角色将客户端与子系统的外部复杂性分隔开,使得客户端只须要与外观角色打交道,而不须要与子系统外部的很多对象打交道。 1.2 定义外观模式:内部与一个子系统的通信通过一个对立的外观角色进行,为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易应用。外观模式又叫门面模式,是一种对象结构型模式。 1.3 结构图 1.4 角色Facade(外观角色):在客户端能够调用这个角色的办法,在外观角色中能够晓得相干的一个或多个子系统的性能和责任,失常状况下将来自客户端的申请委派到对应的子系统中去,传递给相应的子系统对象解决SubSystem(子系统角色):每一个子系统是一个独自的类,也能够是一个类的汇合,实现子系统的性能。每一个子系统都能够被客户端间接调用,或者被外观角色调用,它解决由外观类传过来的申请,子系统并不知道外观类的存在,对于子系统而已,外观角色仅仅是另一个客户端2 典型实现2.1 步骤定义子系统:首先定义子系统,实现一个繁多的性能,解决由客户端传来的申请定义外观角色:外观角色能够晓得一个或多个子系统的性能和责任,将来自客户端的申请委派到对应的子系统去,外观角色对于子系统而言是另一个客户端2.2 外观角色通常实现如下: class Facade{ private SubSystemA subSystemA = new SubSystemA(); private SubSystemB subSystemB = new SubSystemB(); private SubSystemC subSystemC = new SubSystemC(); public void method() { subSystemA.method(); subSystemB.method(); subSystemC.method(); }}class SubSystemA{ public void method() { System.out.println("子系统A"); }}class SubSystemB{ public void method() { System.out.println("子系统B"); }}class SubSystemC{ public void method() { System.out.println("子系统C"); }}3 实例设计一个文件加密零碎,加密流程包含三局部:读取文件,加密文件,保留文件。这三个操作绝对独立,并且封装在三个不同的类中,应用外观模式设计该零碎。子系统类: ...

July 27, 2020 · 2 min · jiezi

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

1.工厂设计模式1.1简略工厂模式1.1.1看一个具体的需要看一个披萨的我的项目:要便于披萨品种的扩大,要便于保护 (1) 披萨的品种很多(比方 GreekPizz、CheesePizz 等)。 (2) 披萨的制作有 prepare,bake, cut, box。 (3) 实现披萨店订购性能。 1.1.2应用传统的形式来实现(1)思路剖析(类图) 代码示例: //将Pizza 类做成形象public abstract class Pizza { protected String name; //名字 //筹备原材料, 不同的披萨不一样,因而,咱们做成形象办法 public abstract void prepare(); public void bake() { System.out.println(name + " baking;"); } public void cut() { System.out.println(name + " cutting;"); } //打包 public void box() { System.out.println(name + " boxing;"); } public void setName(String name) { this.name = name; }}public class PepperPizza extends Pizza { @Override public void prepare() { // TODO Auto-generated method stub System.out.println(" 给胡椒披萨筹备原材料 "); }}public class GreekPizza extends Pizza { @Override public void prepare() { // TODO Auto-generated method stub System.out.println(" 给希腊披萨 筹备原材料 "); }}public class CheesePizza extends Pizza { @Override public void prepare() { // TODO Auto-generated method stub System.out.println(" 给制作奶酪披萨 筹备原材料 "); }}调用代码 ...

July 26, 2020 · 5 min · jiezi

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

1.单例设计模式简介所谓类的单例设计模式,就是采取肯定的办法保障在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个获得其对象实例的办法(静态方法)。比方Hibernate的SessionFactory,它充当数据存储源的代理,并负责创立Session对象。SessionFactory并不是轻量级的,个别状况下,一个我的项目通常只须要一个SessionFactory就够,这是就会应用到单例模式。 2.单例设计模式八种形式单例模式有八种形式:(1) 饿汉式( 动态常量)(2) 饿汉式(动态代码块)(3)懒汉式(线程不平安)(4)懒汉式(线程平安,同步办法)(5) 懒汉式(线程平安,同步代码块)(6) 双重查看(7) 动态外部类(8) 枚举 2.1饿汉式(动态常量)饿汉式(动态常量)利用实例步骤如下:(1) 结构器私有化(避免 new )(2) 类的外部创建对象(3) 向外裸露一个动态的公共办法,获取类的实例 (4) 代码实现 //饿汉式(动态常量)public class Singleton { //1.结构器私有化 private Singleton() { } //2,本类外部能创建对象实例 private final static Singleton instance = new Singleton(); //3.提供一个私有的静态方法,返回实例对象 public static Singleton getInstance() { return instance; }}public class SingletonTest { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance2 = Singleton.getInstance(); System.err.println(instance==instance2); System.err.println("instance.hashCode="+instance.hashCode()); System.err.println("instance2.hashCode="+instance2.hashCode()); }}阐明(1) 长处:这种写法比较简单,就是在类装载的时候就实现实例化。防止了线程同步问题。(2) 毛病:在类装载的时候就实现实例化,没有达到Lazy Loading的成果。如果从始至终从未应用过这个实例,则会造成内存的节约(3) 这种形式基于classloder机制防止了多线程的同步问题,不过,instance在类装载时就实例化,在单例模式中大多数都是调用getInstance办法, 然而导致类装载的起因有很多种,因而不能确定有其余的形式(或者其余的静态方法)导致类装载,这时候初始化instance就没有达到lazy loading的成果(4) 这种单例模式可用, 可能造成内存节约 ...

July 26, 2020 · 3 min · jiezi

关于设计模式:设计模式学习笔记十二装饰模式

1 概述1.1 引言装璜模式能够在不扭转一个对象自身性能的根底上给对象减少额定的新行为。比方,一张照片,不扭转照片自身,减少一个相框。 装璜模式是一种用于代替继承的技术,毋庸定义子类即可给对象动静减少职责,应用对象之间的关联关系来代替继承关系,在装璜模式中引入了装璜类,在装璜类中既能够调用待装璜的原有类办法,还能够减少新的办法,以裁减原有的类性能。 1.2 定义装璜模式:动静地给对象减少一些额定的职责。 就减少对象性能来说,装璜模式比生成子类实现更为灵便,装璜模式是一种对象结构型模式。 1.3 结构图 1.4 角色Component(形象构件类):是具体构件以及形象装璜类的父类,申明了在具体构件中实现的业务办法,它的引入能够使客户端以统一的形式解决未被装璜之后的对象,以实现客户端的通明操作ConcreteComponent(具体构件类):是形象构件类的子类,用于定义具体的构件对象,实现了在形象构件中申明的办法,装璜器能够给它减少额定的职责Decorator(形象装璜类):用于给具体构件类减少职责,然而具体职责在子类实现。形象装璜类保护一个指向形象构件的援用,通过该援用能够调用装璜之前构件对象的办法,并通过子类扩大该办法以达到装璜的目标ConcreteDecorator(具体装璜类):负责向构件中增加新的职责,每一个具体装璜类都定义了一些新的行为,能够调用形象装璜类中定义的办法,并能够减少新的职责用以裁减对象的行为2 典型实现2.1 步骤定义形象构件类:能够是抽象类或者接口,申明业务办法定义具体构件类:继承或实现形象构件,实现具体业务办法定义形象装璜类:继承或实现形象构件,减少一个形象构件公有成员,通过该成员能够调用装璜之前具体构件的办法定义具体装璜类:继承形象装璜类,并且减少装璜行为,在装璜之前调用具体构件办法,接着调用装璜办法2.2 形象构件类简化只有一个业务办法: abstract class Component{ abstract void operation();}2.3 具体构件类继承形象构件: class ConcreteComponent extends Component{ public void operation() { System.out.println("具体构件办法"); }}2.4 形象装璜类class Decorator extends Component{ private Component component; public Decorator(Component component) { this.component = component; } public void operation() { component.operation(); }}形象装璜类须要蕴含一个形象构件的公有成员,以便能够通过setter或构造方法注入不同的具体构件,同时在业务办法中不便调用具体构件未装璜之前的办法。 2.5 具体装璜类class ConcreteDecorator extends Decorator{ public ConcreteDecorator(Component component) { super(component); } public void operation() { super.operation(); newBehavior(); } public void newBehavior() { System.out.println("装璜办法"); }}继承形象装璜类,在业务办法中首先调用父类(形象装璜类)的办法再调用新的装璜办法。 ...

July 26, 2020 · 2 min · jiezi

关于设计模式:设计模式学习笔记十二装饰模式

1 概述1.1 引言装璜模式能够在不扭转一个对象自身性能的根底上给对象减少额定的新行为。比方,一张照片,不扭转照片自身,减少一个相框。 装璜模式是一种用于代替继承的技术,毋庸定义子类即可给对象动静减少职责,应用对象之间的关联关系来代替继承关系,在装璜模式中引入了装璜类,在装璜类中既能够调用待装璜的原有类办法,还能够减少新的办法,以裁减原有的类性能。 1.2 定义装璜模式:动静地给对象减少一些额定的职责。 就减少对象性能来说,装璜模式比生成子类实现更为灵便,装璜模式是一种对象结构型模式。 1.3 结构图 1.4 角色Component(形象构件类):是具体构件以及形象装璜类的父类,申明了在具体构件中实现的业务办法,它的引入能够使客户端以统一的形式解决未被装璜之后的对象,以实现客户端的通明操作ConcreteComponent(具体构件类):是形象构件类的子类,用于定义具体的构件对象,实现了在形象构件中申明的办法,装璜器能够给它减少额定的职责Decorator(形象装璜类):用于给具体构件类减少职责,然而具体职责在子类实现。形象装璜类保护一个指向形象构件的援用,通过该援用能够调用装璜之前构件对象的办法,并通过子类扩大该办法以达到装璜的目标ConcreteDecorator(具体装璜类):负责向构件中增加新的职责,每一个具体装璜类都定义了一些新的行为,能够调用形象装璜类中定义的办法,并能够减少新的职责用以裁减对象的行为2 典型实现2.1 步骤定义形象构件类:能够是抽象类或者接口,申明业务办法定义具体构件类:继承或实现形象构件,实现具体业务办法定义形象装璜类:继承或实现形象构件,减少一个形象构件公有成员,通过该成员能够调用装璜之前具体构件的办法定义具体装璜类:继承形象装璜类,并且减少装璜行为,在装璜之前调用具体构件办法,接着调用装璜办法2.2 形象构件类简化只有一个业务办法: abstract class Component{ abstract void operation();}2.3 具体构件类继承形象构件: class ConcreteComponent extends Component{ public void operation() { System.out.println("具体构件办法"); }}2.4 形象装璜类class Decorator extends Component{ private Component component; public Decorator(Component component) { this.component = component; } public void operation() { component.operation(); }}形象装璜类须要蕴含一个形象构件的公有成员,以便能够通过setter或构造方法注入不同的具体构件,同时在业务办法中不便调用具体构件未装璜之前的办法。 2.5 具体装璜类class ConcreteDecorator extends Decorator{ public ConcreteDecorator(Component component) { super(component); } public void operation() { super.operation(); newBehavior(); } public void newBehavior() { System.out.println("装璜办法"); }}继承形象装璜类,在业务办法中首先调用父类(形象装璜类)的办法再调用新的装璜办法。 ...

July 26, 2020 · 2 min · jiezi

关于设计模式:设计模式学习笔记十一组合模式

1 概述1.1 概述对于树形构造,比方文件目录,一个文件夹中能够蕴含多个文件夹和文件,而一个文件中不能在蕴含子文件或者子文件夹,在这里能够称文件夹为容器,称文件为叶子。 在树形构造中,当容器对象(比方文件夹)的某个办法被调用时,将遍历整个文件夹,寻找也蕴含这个办法的成员对象(容器对象或叶子对象)并调用执行。因为容器对象以及叶子对象在性能上的区别,应用这些对象的代码中必须有区别对待容器对象以及叶子对象,但大多数状况下须要一致性解决它们。 组合模式为解决此类问题而生,它能够让叶子对象以及容器对象的应用具备一致性。 1.2 定义组合模式:组合多个对象造成树形构造以示意具备“整体-局部”关系的层次结构。组合模式对单个对象(叶子对象)和组合对象(容器对象)的应用具备一致性。组合模式又叫“局部-整体”模式,它是一种对象结构型模式。 1.3 结构图 1.4 角色Component(形象构件):能够是接口或者抽象类,为叶子构件和容器构件对象申明接口,在该角色中能够蕴含所有子类共有行为的申明和实现。在形象构件中定义了拜访以及治理它的子构件的办法,例如减少/删除/获取子构件Leaf(叶子构件):示意叶子节点对象,叶子节点没有子节点,它实现了在形象构件中定义的行为,对于拜访以及治理子构件的办法,通常会抛出异样Composite(容器构件):示意容器节点对象,容器节点蕴含子节点,其子节点能够是叶子节点,也能够是容器节点,它提供一个汇合用于存储子节点,实现了在形象构件中定义的行为,包含拜访以及治理子构件的办法2 典型实现2.1 步骤组合模式的要害是定义了一个形象构件类,它既能够示意叶子也能够示意容器,客户端针对该形象构件进行编程,毋庸晓得到底是叶子还是容器,同时容器对象与形象构件之间须要建设一个聚合关联关系,在容器对象中既能够蕴含叶子也能够蕴含容器,以此实现递归组合,造成树形构造。 因而首先须要定义形象构件类,通用步骤如下: 定义形象构件:定义形象构件类,增加四个根本办法:减少/删除/获取成员+业务办法,能够将形象构件类定义为抽象类或者接口定义叶子构件:继承或实现形象构件类,笼罩或实现具体业务办法,同时对于治理或拜访子构件的办法提供异样解决或谬误提醒定义容器构件:继承或实现形象构件类,笼罩或实现形象构件中的所有办法,一般来说容器构件会蕴含一个汇合公有成员用于保留形象构件,在业务办法中对这个汇合进行遍历从而实现递归调用2.2 形象构件形象构件个别定义如下: abstract class Component{ abstract void add(Component c); abstract void remove(Component c); abstract Component getChild(int i); abstract void operation();}2.3 叶子构件class Leaf extends Component{ public void add(Component c) { //叶子构件不能拜访该办法 System.out.println("谬误,不能拜访增加构件办法!"); } public void remove(Component c) { //叶子构件不能拜访该办法 System.out.println("谬误,不能拜访删除构件办法!"); } public Component getChild(int i) { //叶子构件不能拜访该办法 System.out.println("谬误,不能拜访获取构件办法!"); return null; } public void operation() { System.out.println("叶子业务办法"); }}叶子构件只须要笼罩具体业务办法opeartion,对于治理子构件的办法能够提醒谬误或者抛出异样来解决。 ...

July 26, 2020 · 3 min · jiezi

关于设计模式:设计模式学习笔记十桥接模式

1 定义桥接模式:将形象局部与其实现局部拆散,使它们都能够独立地变动。它是一种对象结构型模式,又称为柄体模式或者接口模式。 2 概述桥接模式是一种很实用的结构型设计模式,如果软件系统中某个类存在两个独立变动的维度,通过该模式能够将这两个维度分离出来,使两者能够独立扩大,让零碎变得更加合乎SRP。 比方,设计一个跨平台的图像浏览零碎,反对的图片格式包含: PNGBMPJPGGIF等等,而反对的零碎包含: WindowsUnixLinux等等,这样,零碎与图片格式就是两个不同的维度,能够利用桥接模式将这两个维度拆散,使得它们能够独立变动,减少新的图片格式或者新的零碎时,都不会对另一个维度造成任何影响。 3 角色Abstraction(抽象类):用于定义抽象类的接口,个别是抽象类而不是接口,具备一个Implementor的成员,与Implementor为关联关系,既能够蕴含形象的业务办法,也能够蕴含具体业务办法RefinedAbstraction(裁减抽象类):裁减由Abstraction定义的接口,通常为具体类,实现了在Abstraction中的形象业务办法,同时能够调用Implementor中的业务办法Implementor(实现类接口):实现类的接口,相比起Abstractoin提供的更多更简单的操作,Implementor个别只提供基本操作,具体实现交由子类解决ConcreteImplementor(具体实现类):具体实现Implementor接口,不同的ConcreteImplementor提供不同实现的基本操作结构图如下: 4 步骤辨认维度:首先辨认出零碎中两个独立变动的维度继承:辨认出维度后,将它们设计为两个独立的继承等级构造,比方下面的图片格式以及零碎,将图片格式与零碎设为形象层,而BMP,GIF等继承图片格式形象层,Windows等具体系统集成零碎形象层建设形象耦合:在形象层建设一个形象关联扩大:建设形象耦合后,依据须要对两个维度进行独立扩大,比方减少新的图片格式WBEP,减少新的操作系统Mac等5 实例跨平台的图片浏览零碎,反对的图片格式包含PNG,JPG,BMP,GIF等,反对的零碎包含Linux,Unix,Windows等,应用桥接模式设计。图片维度:抽象类Image,BMP,GIF等继承Image,Image具备一个ImageShow的成员变量零碎维度:Linux,Unix,Windows实现图片显示接口ImageShow代码如下: public class Test{ public static void main(String[] args) { Image image = new GIF(); image.setImageShow(new Linux()); image.show(); }}//Image抽象类abstract class Image{ protected ImageShow imageShow; public void setImageShow(ImageShow imageShow) { this.imageShow = imageShow; } public abstract show();}class BMP extends Image{ @Override public void show() { imageShow.show("BMP"); }}class GIF extends Image{ @Override public void show() { imageShow.show("GIF"); }}class PNG extends Image{ @Override public void show() { imageShow.show("PNG"); }}class JPG extends Image{ @Override public void show() { imageShow.show("JPG"); }}//图片显示接口interface ImageShow{ void show(String name);}class Windows implements ImageShow{ @Override public void show(String name) { System.out.println("Windows show "+name); }}class Linux implements ImageShow{ @Override public void show(String name) { System.out.println("Linux show "+name); }}class Unix implements ImageShow{ @Override public void show(String name) { System.out.println("Unix show "+name); }}更换图片格式只须要批改Image的父类: ...

July 25, 2020 · 2 min · jiezi

关于设计模式:设计模式学习笔记九适配器模式

1 适配器模式1.1 定义将一个接口转换为客户心愿的另一个接口,使接口不兼容的那些类能够一起工作,别名为包装器。适配器中的接口是狭义的接口,能够示意一个办法或者办法的汇合。 适配器模式既能够作为类结构型模式,也能够作为对象结构型模式。 1.2 分类依据适配器与适配者类的关系不同,能够分为对象适配器模式以及类适配器模式。 1.2.1 对象适配器模式对象适配器模式就是适配器与适配者之间是关联关系。结构图如下: 1.2.2 类适配器模式类适配器模式就是适配器与适配者之间是继承或实现关系。结构图如下:因为语言个性的限度,比方Java,C#不反对多重继承,类适配器模式受到很多限度,例如Target如果不是接口而是一个类,就无奈应用类适配器模式。此外如果适配者为final类也无奈应用适配器模式,在Java等语言中大部分状况下应用对象适配器模式。 1.3 角色Target(指标抽象类):指标抽象类定义客户所需的接口,能够是一个抽象类或接口,也能够是一个具体类Adapter(适配器类):适配器能够调用另一个接口,作为一个转换器,对Adaptee和Target进行适配。适配器类是适配器模式的外围,在对象适配器模式中,它通过继承Target并关联一个Adaptee对象使两者产生分割Adaptee(适配者类):适配者即被适配的角色,它定义了一个曾经存在的接口,这个接口须要适配,适配者类个别是一个具体类,蕴含了客户心愿应用的业务办法,在某些状况下可能没有适配者类的源代码2 实例2.1 对象适配器Target类以及实现了Target的类: interface Target{ void request();}class ConcreteTarget implements Target{ @Override public void request() { System.out.println("具体Target办法"); }}适配者类: class Adaptee{ public void specificRequest() { System.out.println("Adaptee办法"); }}适配器类(实现了Target,适配者作为成员变量): class Adapter implements Target{ private Adaptee adaptee = new Adaptee(); @Override public void request() { adaptee.specificRequest(); }}测试: public class Test{ public static void main(String[] args) { Target target = new ConcreteTarget(); target.request(); Target adapter = new Adapter(); adapter.request(); }}2.2 类适配器在上述对象适配器的根底上,适配者与Target放弃不变,适配器继承了适配者并实现了Target,同时勾销了适配者作为成员变量,在办法内间接调用super.xxx,也就是适配者的办法: ...

July 24, 2020 · 2 min · jiezi

关于设计模式:设计模式学习笔记九适配器模式

1 适配器模式1.1 定义将一个接口转换为客户心愿的另一个接口,使接口不兼容的那些类能够一起工作,别名为包装器。适配器中的接口是狭义的接口,能够示意一个办法或者办法的汇合。 适配器模式既能够作为类结构型模式,也能够作为对象结构型模式。 1.2 分类依据适配器与适配者类的关系不同,能够分为对象适配器模式以及类适配器模式。 1.2.1 对象适配器模式对象适配器模式就是适配器与适配者之间是关联关系。结构图如下: 1.2.2 类适配器模式类适配器模式就是适配器与适配者之间是继承或实现关系。结构图如下:因为语言个性的限度,比方Java,C#不反对多重继承,类适配器模式受到很多限度,例如Target如果不是接口而是一个类,就无奈应用类适配器模式。此外如果适配者为final类也无奈应用适配器模式,在Java等语言中大部分状况下应用对象适配器模式。 1.3 角色Target(指标抽象类):指标抽象类定义客户所需的接口,能够是一个抽象类或接口,也能够是一个具体类Adapter(适配器类):适配器能够调用另一个接口,作为一个转换器,对Adaptee和Target进行适配。适配器类是适配器模式的外围,在对象适配器模式中,它通过继承Target并关联一个Adaptee对象使两者产生分割Adaptee(适配者类):适配者即被适配的角色,它定义了一个曾经存在的接口,这个接口须要适配,适配者类个别是一个具体类,蕴含了客户心愿应用的业务办法,在某些状况下可能没有适配者类的源代码2 实例2.1 对象适配器Target类以及实现了Target的类: interface Target{ void request();}class ConcreteTarget implements Target{ @Override public void request() { System.out.println("具体Target办法"); }}适配者类: class Adaptee{ public void specificRequest() { System.out.println("Adaptee办法"); }}适配器类(实现了Target,适配者作为成员变量): class Adapter implements Target{ private Adaptee adaptee = new Adaptee(); @Override public void request() { adaptee.specificRequest(); }}测试: public class Test{ public static void main(String[] args) { Target target = new ConcreteTarget(); target.request(); Target adapter = new Adapter(); adapter.request(); }}2.2 类适配器在上述对象适配器的根底上,适配者与Target放弃不变,适配器继承了适配者并实现了Target,同时勾销了适配者作为成员变量,在办法内间接调用super.xxx,也就是适配者的办法: ...

July 24, 2020 · 2 min · jiezi

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

1.本人写的单例模式 //双重测验锁 双重测验锁模式(double checked locking pattern),// 是一种应用同步块加锁的办法。程序员称其为双重查看锁,// 因为会有两次查看 instance == null,一次是在同步块外,一次是在同步块内。// 为什么在同步块内还要再测验一次?因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次测验的话就会生成多个实例了。public class SingletonDemo04 { private SingletonDemo04 singletonDemo04; private static boolean flag = false; private SingletonDemo04() { if (flag == false) { flag = !flag; } else { throw new RuntimeException("单例模式被进犯!"); } } public SingletonDemo04 getInstance() { if (singletonDemo04 == null) { synchronized (this) { if (singletonDemo04 == null) { singletonDemo04 = new SingletonDemo04(); } } } return singletonDemo04; } public static void main(String[] args) { System.out.println("main"); SingletonDemo04 s1 = new SingletonDemo04().getInstance(); SingletonDemo04 s2 = new SingletonDemo04().getInstance(); System.out.println(s1 == s2); }}

July 20, 2020 · 1 min · jiezi

关于设计模式:设计模式学习笔记八建造者模式

1 建造者模式1.1 定义建造者模式:将一个简单的对象的构建与它的示意拆散,使得同样的构建过程能够创立不同的示意。建造者模式是一种对象创立型模式。 建造者模式是较为简单的创立型模式,它将客户端与蕴含多个组成部分(或部件)的简单对象的创立过程拆散,客户端毋庸晓得简单对象的外部组成部分与拆卸形式,只须要晓得所需的建造者类型即可。建造者模式关注一步一步地创立一个简单对象,不同的具体建造者定义了不同的创立过程,且具体建造者互相独立,减少新的建造者十分不便,毋庸批改已有代码,零碎具备较好的扩展性。 1.2 简单对象建造者模式中用到了简单对象这个概念。简单对象就是指那些蕴含多个成员变量的对象,这些成员变量也叫部件或者整机,例如汽车包含方向盘,发动机,轮胎等 ,汽车就是简单对象,方向盘,发动机以及轮胎就是汽车的部件。 1.3 结构图 1.4 角色建造者模式蕴含以下四个角色: Builder(形象建造者):为创立一个产品Product对象的各个部件指定形象接口,在该接口中个别申明两类办法,一类是buildXXX()办法,用于创立简单对象的各个局部(部件),另一类是是getResult(),用于返回简单对象。Builder既能够是抽象类,也能够是接口ConcreteBuilder(具体建造者):实现了Builder接口或者继承了Builder类,实现各个部件的具体结构和拆卸办法,定义并明确其所创立的简单对象,也能够提供一个办法返回创立好的简单对象Product(产品角色):是被构建的简单对象,蕴含多个组成部件,具体建造者创立该产品的外部示意并定义其拆卸过程Director(指挥者):指挥者又叫导演类,简单安顿简单对象的建造秩序,指挥者与形象建造者之间存在关联关系,能够在其construct()建造办法中调用建造者对象的部件结构以及拆卸办法,实现简单对象的建造。客户端个别只须要与导演类进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象,而后通过导演类的构造函数或者setter将该对象传入导演类中1.4.1 Product一般来说Product是一个简单对象,典型的定义如下: class Product{ private type1 part1; private type2 part2; private type3 part3; //getter + setter ...}其中type1,type2等指各种不同的类型,一般来说会有嵌套类。 1.4.2 Builder形象建造者的典型定义如下: abstract class Builder{ protected Product product = new Product(); public abstract void buildPart1(); public abstract void buildPart2(); public abstract void buildPart3(); public Product getResult() { return product; }}形象建造者中申明了一系列buildXXX办法,用于创立Product的各个部件,具体创立过程在ConcreteBuilder中实现,getResult()返回已创立实现的Product。 1.4.3 ConcreteBuilderConcreteBuilder实现了Builder中的buildXXX办法,通过调用Product的setter来实现给产品对象的各局部赋值。不同的ConcreteBuilder在实现buildXXX是将有所区别,比方传入Product的setter参数的不同。另外在有些ConcreteBuilder中某些buildXXX毋庸实现(提供一个空实现),这些对客户端来说毋庸关怀,客户端只须要晓得具体建造者的类型即可。典型定义如下: class ConcreteBuilder extends Builder{ public void buildPart1() { product.setPart1("part1"); } public void buildPart2() { product.setPart2("part2"); } public void buildPart3() { product.setPart3("part3"); } public Product getResult() { return product; }}1.4.4 DirectorDirector类次要有两个作用: ...

July 18, 2020 · 3 min · jiezi

设计模式学习笔记六抽象工厂模式

1 相干术语在理解形象工厂模式之前,首先来理解一下两个术语: 产品等级构造产品族1.1 产品等级构造产品等级构造也就是产品的继承构造,例如一个抽象类是电视机,子类有不同品牌的电视机,比方海尔电视机,海信电视机,TCL电视机,而形象电视机与具体品牌的电视机之间形成了一个产品等级构造,形象电视机是父类,而具体品牌的电视机是子类。 1.2 产品族产品族是指由一个同一个工厂产生的位于不同产品等级构造中的一组产品,例如海尔电器工厂生产的海尔电视机,海尔电冰箱。海尔电视机位于电视机产品等级构造中,海尔电冰箱位于电冰箱产品等级构造中,海尔电视机与海尔电冰箱独特形成了一个产品族。 两者示意图如下: 2 形象工厂模式**形象工厂模式:提供一个创立一系列相干或相互依赖对象的接口,而无须指定它们具体的类。形象工厂模式又叫Kit模式,是一种对象创立型模式。** 结构图如下: 形象工厂模式蕴含四个角色: AbstractFactory(形象工厂):申明了一组用于创立一族产品的办法,每一个办法对应一种产品ConcreteFactory(具体工厂):实现了在形象工厂中申明的创立产品的办法,生成一组具体产品,这些产品形成了一个产品族,每一个产品都位于某个产品的等级构造中AbstractProduct(形象产品):为每种产品申明接口,在形象产品中申明了产品所具备的业务办法ConcreteProduct(具体产品):定义具体工厂生产的具体对象,实现在形象层产品接口中申明的业务办法3 实例界面皮肤库设计:开发一套皮肤库,用户能够通过菜单抉择皮肤,不同的皮肤提供视觉不同的按钮,文本框等UI元素。这里简略起见假如开发两套皮肤: 秋季皮肤(SpringSkin)冬季皮肤(SummerSkin)每套皮肤具备以下UI元素: 按钮(Button)文本框(TextField)组合框(ComboBox)首先是UI元素,包含形象元素以及具体元素: interface Button{ void display();}class SpringButton implements Button{ public void display() { System.out.println("秋季皮肤按钮"); }}class SummerButton implements Button{ public void display() { System.out.println("冬季皮肤按钮"); }}interface TextField{ void display();}class SpringTextField implements TextField{ public void display() { System.out.println("秋季皮肤文本框"); }}class SummerTextField implements TextField{ public void display() { System.out.println("冬季皮肤文本框"); }}interface ComboBox{ void display();}class SpringComboBox implements ComboBox{ public void display() { System.out.println("秋季皮肤组合框"); }}class SummerComboBox implements ComboBox{ public void display() { System.out.println("冬季皮肤组合框"); }}接着是工厂类,包含形象工厂以及具体工厂: ...

July 16, 2020 · 1 min · jiezi

设计模式学习笔记五工厂方法模式

1 前言只管简略工厂模式实现了对象的创立和应用拆散,然而依然存在以下两个问题: 工厂类过于宏大,蕴含了大量的判断代码,导致保护和测试难度增大零碎扩大不灵便,如果减少了新的产品类型,必须批改动态工厂办法的业务逻辑,违反了开闭准则具体产品与工厂类之间的耦合度高,重大影响了零碎的灵活性和扩展性一个更好的方法是应用工厂办法模式。 2 工厂办法模式工厂办法模式:定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂办法又简称工厂模式或虚构结构器模式或多态工厂模式,让一个类的实例化提早到其子类,是一品种创立型模式。结构图如下: 工厂办法模式蕴含以下四个角色: Product(形象产品):定义产品的接口,是工厂办法模式所创立的超类型,也就是产品对象的公共父类ConcreteProduct(具体产品):实现了形象产品接口,某种类型的具体产品由专门的具体工厂创立,具体工厂与具体产品一一对应Factory(形象工厂):在形象工厂类中,申明了工厂办法,用于返回一个产品。形象工厂是工厂办法模式的外围,所有创建对象的工厂类都必须实现该接口ConcreteFactory(具体工厂):它是形象工厂类的子类,实现了形象工厂中定义的工厂办法,并可由客户端调用,返回一个具体产品类的实例3 实例日志记录器的设计:该记录器能够通过多种路径保留零碎的运行日志,例如文件记录或者数据库记录。代码如下: public class Test{ public static void main(String[] args) { LoggerFactory factory = new FileLoggerFactory(); Logger logger = factory.createLogger(); logger.log(); }}//形象产品interface Logger{ void log();}//具体产品:DatabaseLoggerclass DatabaseLogger implements Logger{ public void log() { System.out.println("数据库日志记录"); }}//具体产品:FileLoggerclass FileLogger implements Logger{ public void log() { System.out.println("文件日志记录"); }}//形象工厂interface LoggerFactory{ Logger createLogger();}//具体工厂:DatabaseLoggerFactoryclass DatabaseLoggerFactory implements LoggerFactory{ public Logger createLogger() { return new DatabaseLogger(); }}//具体工厂:FileLoggerFactoryclass FileLoggerFactory implements LoggerFactory{ public Logger createLogger() { return new FileLogger(); }}4 暗藏能够把形象工厂设置为抽象类,工厂办法间接能够对客户端暗藏,也就是说能够间接通过形象工厂调用具体产品类的业务办法,客户端无需创立具体产品,间接通过工厂类调用即可,代码批改如下(形象产品以及具体产品类不必批改): ...

July 16, 2020 · 1 min · jiezi

设计模式你精通那高并发中的设计模式呢是不是也精通呢

在开始明天的内容之前,是不是先来温习一下设计模式,毕竟不是所有人对于设计模式都是精通的状态,那这个时候,先温习一下再进行新的步骤,不失为一种很好的状态呀 设计模式因为图谱开展之后切实是太大了,就不开展了,给大家截取一部分,内容涵盖23种设计模式,然而毕竟不是重点 设计准则对于设计准则,在上方的设计模式图中,就介绍了6大设计模式,这一篇中,进行了分类的具体解说,算是附赠图谱吧 须要下面2份脑图的,关注+转发后,私信“材料”即可查看获取形式而在回顾了下面的设计模式的相干内容之后,接下来就是本文的重点了,解说几种常见并行模式, 具体目录构造如下图. 单例单例是最常见的一种设计模式, 个别用于全局对象治理, 比方xml配置读写之类的. 个别分为懒汉式, 饿汉式. 懒汉式: 办法上加synchronized 1 public static synchronized Singleton getInstance() { 2          if (single == null) { 3              single = new Singleton(); 4          } 5         return single; 6 } 这种形式, 因为每次获取示例都要获取锁, 不举荐应用, 性能较差 懒汉式: 应用双检锁 + volatile 1     private volatile Singleton singleton = null;  2     public static Singleton getInstance() {  3         if (singleton == null) {  4             synchronized (Singleton.class) {  5                 if (singleton == null) {  6                     singleton = new Singleton();  7                 }  8             }  9         } 10         return singleton; 11     } 本形式是对间接在办法上加锁的一个优化, 益处在于只有第一次初始化获取了锁. 后续调用getInstance曾经是无锁状态. 只是写法上略微繁琐点. 至于为什么要volatile关键字, 次要波及到jdk指令重排, 详见之前的博文: Java内存模型与指令重排 懒汉式: 应用动态外部类 1 public class Singleton { 2     private static class LazyHolder { 3        private static final Singleton INSTANCE = new Singleton(); 4     } 5     private Singleton (){} 6     public static final Singleton getInstance() { 7        return LazyHolder.INSTANCE; 8     } 9 } ...

July 16, 2020 · 4 min · jiezi

设计模式学习笔记四简单工厂模式

1 定义简略工厂模式(Simple Factory Pattern):定义一个工厂类,它能够依据参数的不同返回不同类的实例,被创立的实例通常都具备独特的父类。 因为在简略工厂模式用于创立实例的办法是动态的办法,因而简略工厂模式又被称为动态工厂办法模式,它属于类创立型模式。 只管简略工厂模式不属于GoF23种设计模式之一,然而理论中用处宽泛,并且能够作为学习“工厂办法模式”以及“形象工厂模式”的根底。 2 构造 由图可知蕴含以下三个角色: Factory(工厂角色):即工厂类,负责实现创立所有产品实例的外部逻辑,工厂类能够被外界间接调用,创立所须要的产品对象,在工厂类中提供了一个动态工厂办法用于获取产品Product(形象产品角色):是工厂类所创立的所有对象的父类,封装了各种产品对象的私有办法。Product会进步零碎的灵活性,使得在工厂类只须要定义一个通用的工厂产品办法,因为所有创立的具体产品都是其子类对象ConcreteProduct(具体产品角色):所有被创立的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了形象产品角色,须要实现在形象产品中申明的形象办法3 实例某公司须要开发一个图表库,该图表库能够提供各种不同外观的图表,例如柱状图,折线图等等。 首先能够先设计一个形象图表类(这里是一个接口): interface Chart{ void display();}接着各种具体产品类(柱状图,折线图,饼状图等)实现该接口即可: class HistogramChart implements Chart{ public HistogramChart() { System.out.println("创立柱状图"); } public void display() { System.out.println("显示柱状图"); }}class PieChart implements Chart{ public PieChart() { System.out.println("创立饼状图"); } public void display() { System.out.println("显示饼状图"); }}class LineChart implements Chart{ public LineChart() { System.out.println("创立折线图"); } public void display() { System.out.println("显示折线图"); }}最初是工厂类,为了不便加上了枚举参数: class Factory{ public static Chart getChart(Charts charts) { switch(charts) { case PIE_CHART: return new PieChart(); case LINE_CHART: return new LineChart(); case HISTOGRAM_CHART: return new HistogramChart(); default: return null; } }}enum Charts{ PIE_CHART,LINE_CHART,HISTOGRAM_CHART;}测试: ...

July 13, 2020 · 1 min · jiezi

重学-Java-设计模式PDF-出炉了-小傅哥肝了50天写出18万字271页的实战编程资料

作者:小傅哥博客:https://bugstack.cn 积淀、分享、成长,让本人和别人都能有所播种!????一、前言我收缩了????,在编写完上一本PDF《字节码编程》被下载了2000份当前,蠢蠢欲动开始打算第二本。于是从????5月20日那天投身实战型设计模式打磨,通过模仿互联网业务开发理论需要作为学习场景,解说设计模式。 全书共计22个实在业务场景对应59组案例工程、编写了18万字271页的PDF、从5月20日开始耗时50天打造实现。 ????鉴于作者程度无限,如果书中含有不易了解的内容,肯定是作者在编写的过程中短少必要的形容和严格的校准,感激把你的意见或者疑难提交给我,也欢送与我多一些交互,相互提高独特成长。 二、简介 欢送来到这里,很快乐你将拿到这本电子书,如果你能保持看完并依照书中的例子进行实际,那么在编程开发的世界里,就又多了一个能够写出良好代码的人,同时也为架构师造就储备了一个人才。 可能在此之前你也多少理解过设计模式,但在理论的业务开发中应用却不多,少数时候都是大面积沉积ifelse组装业务流程,对于一次次的需要迭代和逻辑补充,只能七拼八凑Ctrl+C、Ctrl+V。 所以为了能让更多的程序员????????更好的承受设计思维和架构思维,并能使用到理论的业务场景。本书的作者小傅哥,投入50天工夫,从互联网理论业务开发中抽离出,交易、营销、秒杀、中间件、源码等22个实在场景,来学习设计模式实际应用的利用可上手技能。 1. 谁创造了设计模式?设计模式的概念最早是由 克里斯托佛·亚历山大 在其著述 《修建模式语言》 中首次提出的。 本书介绍了城市设计的 “语言”,提供了253个形容城镇、邻里、住宅、花园、房间及西部结构的模式, 而此类 “语言” 的根本单元就是模式。起初,埃里希·伽玛、 约翰·弗利赛德斯、 拉尔夫·约翰逊 和 理查德·赫尔姆 这四位作者承受了模式的概念。 1994 年, 他们出版了 《设计模式: 可复用面向对象软件的根底》 一书, 将设计模式的概念利用到程序开发畛域中。 其实有一部分人并没有仔细阅读过设计模式的相干书籍和材料,但仍旧能够编写出优良的代码。这次要是因为在通过泛滥我的项目的锻炼和对程序设计的一直谋求,从而在多年编程历程上提炼进去的心得体会。而这份教训最终会与设计模式提到的内容简直统一,同样会要求高内聚、低耦合、可扩大、可复用。你可能也遇到相似的经验,在学习一些框架的源码时,发现它里的某些设计和你在做开发时一样。 2. 我怎么学不会设计模式?钱也花了,书也买了。代码还是一坨一坨的!设计模式是由多年的教训提炼进去开发指导思想。就像我通知你自行车怎么骑、汽车怎么开,但只有你没跑过几千公里,你能记住的只是实践,想上道仍旧很慌! 所以,本设计模式专题系列开始,会带着你应用设计模式的思维去优化代码。从而学习设计模式的心得并融入给本人。当然这里还须要多加练习,肯定是人车合一,能力站在设计模式的根底上构建出更加正当的代码。 3. 适宜人群具备肯定编程根底在工作1-3年的研发人员心愿通过此书晋升编码思维,剔除到代码中的坏滋味有志愿成为架构师,但还处在肯定瓶颈期学习过设计模式,可是始终想找到一本能够落地实在场景参照的书籍4. 我能学到什么优化平时开发中的ifelse语句,让代码更加整洁看设计模式不再是用实践生吞活剥,这次能够有点用站在更高的角度去对待编程开发,学会更多的面向对象的思维,尤其是;接口、抽象类、多态等应用升职、加薪,良好的代码是效力晋升的根底,成为本组编码最靓的精力小伙5. 浏览倡议本书属于实战型而不是实践介绍类书籍,每一章节都有对应的残缺代码,学习的过程须要参考书中的章节与代码一起学习,同时在学习的过程中须要理解并运行代码。学习实现后进行知识点的总结,以及思考????这样的设计模式在本人的业务场景中须要如何应用。 三、书中目录设计模式遵循六大准则;繁多职责(一个类和办法只做一件事)、里氏替换(多态,子类可扩大父类)、依赖倒置(细节依赖形象,上层依赖下层)、接口隔离(建设繁多接口)、迪米特准则(起码晓得,升高耦合)、开闭准则(形象架构,扩大实现),会在具体的设计模式章节中,进行体现。 1. 创立型模式这类模式提供创建对象的机制, 可能晋升已有代码的灵活性和可复用性。 序号类型图稿业务场景实现要点1工厂办法多种类型商品不同接口,对立发奖服务搭建场景定义一个创建对象的接口,让其子类本人决定实例化哪一个工厂类,工厂模式使其创立过程提早到子类进行。2形象工厂替换Redis双集群降级,代理类形象场景提供一个创立一系列相干或相互依赖对象的接口,而无需指定它们具体的类。3生成器各项装修物料组合套餐选配场景将一个简单的构建与其示意相拆散,使得同样的构建过程能够创立不同的示意。4原型上机考试多套试,每人题目和答案乱序排列场景用原型实例指定创建对象的品种,并且通过拷贝这些原型创立新的对象。5单例7种单例模式案例,Effective Java 作者举荐枚举单例模式保障一个类仅有一个实例,并提供一个拜访它的全局拜访点。2. 结构型模式这类模式介绍如何将对象和类组装成较大的构造, 并同时放弃构造的灵便和高效。 序号类型图稿业务场景实现要点1适配器从多个MQ音讯体中,抽取指定字段值场景将一个类的接口转换成客户心愿的另外一个接口。适配器模式使得本来因为接口不兼容而不能一起工作的那些类能够一起工作。2桥接多领取渠道(微信、支付宝)与多领取模式(刷脸、指纹)场景将形象局部与实现局部拆散,使它们都能够独立的变动。3组合营销差异化人群发券,决策树引擎搭建场景将对象组合成树形构造以示意"局部-整体"的层次结构。组合模式使得用户对单个对象和组合对象的应用具备一致性。4装璜SSO单点登录性能扩大,减少拦挡用户拜访办法范畴场景动静地给一个对象增加一些额定的职责。就减少性能来说,装璜器模式相比生成子类更为灵便。5外观基于SpringBoot开发门面模式中间件,对立管制接口白名单场景为子系统中的一组接口提供一个统一的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易应用。6享元基于Redis秒杀,提供流动与库存信息查问场景使用共享技术无效地反对大量细粒度的对象。7代理模仿mybatis-spring中定义DAO接口,应用代理类形式操作数据库原理实现场景为其余对象提供一种代理以管制对这个对象的拜访。3. 行为模式这类模式负责对象间的高效沟通和职责委派。 序号类型图稿业务场景实现要点1责任链模仿618电商大促期间,我的项目上线流程多级负责人审批场景防止申请发送者与接收者耦合在一起,让多个对象都有可能接管申请,将这些对象连接成一条链,并且沿着这条链传递申请,直到有对象解决它为止。2命令模仿低档餐厅八大菜系,小二点单厨师烹饪场景将一个申请封装成一个对象,从而使您能够用不同的申请对客户进行参数化。3迭代器模仿公司组织架构树结构关系,深度迭代遍历人员信息输入场景提供一种办法程序拜访一个聚合对象中各个元素, 而又毋庸裸露该对象的外部示意。4中介者依照Mybatis原理手写ORM框架,给JDBC形式操作数据库减少中介者场景用一个中介对象来封装一系列的对象交互,中介者使各对象不须要显式地互相援用,从而使其耦合涣散,而且能够独立地扭转它们之间的交互。5备忘录模仿互联网零碎上线过程中,配置文件回滚场景在不毁坏封装性的前提下,捕捉一个对象的外部状态,并在该对象之外保留这个状态。6观察者模仿相似小客车指标摇号过程,监听音讯告诉用户中签场景定义对象间的一种一对多的依赖关系,当一个对象的状态产生扭转时,所有依赖于它的对象都失去告诉并被自动更新。7状态模拟系统营销流动,状态流程审核公布上线场景容许对象在外部状态产生扭转时扭转它的行为,对象看起来如同批改了它的类。8策略模仿多种营销类型优惠券,折扣金额计算策略场景定义一系列的算法,把它们一个个封装起来, 并且使它们可互相替换。9模板办法模仿爬虫各类电商商品,生成营销推广海报场景定义一个操作中的算法的骨架,而将一些步骤提早到子类中。模板办法使得子类能够不扭转一个算法的构造即可重定义该算法的某些特定步骤。10访问者模仿家长与校长,对学生和老师的不同视角信息的拜访场景次要将数据结构与数据操作拆散。以上图稿和局部形容参考;https://refactoringguru.cn、https://www.runoob.com/design-pattern/visitor-pattern.html 四、PDF????下载下载前,一点对原创作者的反对申请????,点赞、在看、分享、留言、赞叹,实现任何一样都能够取得????这本PDF书籍。 1. 可取得内容包含《重学 Java 设计模式》PDF 书籍一本59个对应的工程案例源码一套在线浏览版学习了材料2. 获取形式扫描下方二维码加专栏学习群,凡进群者都送书籍一本增加小傅哥微信(fustack)获取PDF书籍公众号内回复PDF下载,你会取得一个连贯,关上后右侧菜单 -> 精选 -> 值得一看的好书,外面对应也有这本书籍???? 五、收个尾????????走过的路会留下脚印,????????码过的文会盛满四季。 ...

July 13, 2020 · 1 min · jiezi

设计模式学习笔记三单例模式

1 定义有时候为了节约系统资源,须要确保零碎中某个类只有惟一一个实例,当这个实例创立胜利之后,无奈再创立一个同类型的其余对象,所有的操作都只能基于这个惟一的实例,这是单例模式的动机所在。 单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个零碎提供这个实例,这个类称为单例类,它提供全局拜访的办法。单例模式是一种对象创立型模式。 2 要点某个类只能有一个实例它必须自行创立这个实例它必须自行向整个零碎提供这个实例3 通用步骤一般来说把一个一般类重构为一个单例类须要以下三步: 构造函数私有化:也就是禁止内部间接应用new等创建对象定义一个动态类成员保留实例减少一个相似getInstance()的私有静态方法来获取实例因而一般来说单例模式的结构图如下: 4 实例上面以一个简化的负载均衡器设计进行单例模式的阐明。某个软件须要应用一个全局惟一的负载均衡器,设计如下: public class LoadBalancer{ private static LoadBalancer instance = null; private LoadBalancer(){} public static LoadBalancer getInstance() { return instance == null ? instance = new LoadBalancer() : instance; } public static void main(String[] args) { LoadBalancer balancer1 = LoadBalancer.getInstance(); LoadBalancer balancer2 = LoadBalancer.getInstance(); System.out.println(balancer1 == balancer2); }}这是最简略的单例类的设计,获取实例时仅仅判断是否为null,没有思考到线程问题。也就是说,多个线程同时获取实例时,还是会产生多个实例,一般来说,常见的解决形式如下: 饿汉式单例懒汉式单例IoDH5 饿汉式单例饿汉式单例就是在一般的单例类根底上,在定义动态变量时就间接实例化,因而在类加载的时候就曾经创立了单例对象,而且在获取实例时不须要进行判空操作间接返回实例即可: public class LoadBalancer{ private static LoadBalancer instance = new LoadBalancer(); private LoadBalancer(){} public static LoadBalancer getInstance() { return instance; }}当类被加载时,动态变量instance被初始化,类的公有构造方法将被调用,单例类的惟一实例将被创立。 ...

July 12, 2020 · 2 min · jiezi

设计模式学习笔记二UML与面向对象设计原则

1 UML1.1 UMLUML(Unified Modeling Language)是对立建模语言,1997年11月UML1.1版本提交给OMG并正式通过,成为建模语言的个那个也规范。2003年6月UML2.0取得正式通过。 1.2 UML个性U(Unified):对立,UML交融了多种优良的面向对象建模办法以及多种失去认可的软件工程办法,打消了因办法林立且互相独立而带来的种种不便,集众家之长,股名“对立”。通过对立的示意办法能够让不同常识背景的领域专家,系统分析设计人员以及开发人员能够不便地交换M(Modeling):UML是一种通用的可视化建模语言,不同与编程语言,UML通过一些规范的图形符号和文字来对系统进行建模,用于对软件进行形容,可视化解决,结构零碎制品的文档。UML实用于各种软件开发办法,软件生命周期的各个阶段,各种应用领域以及各种开发工具L(Language):UML是一种语言,也就意味着它有属于本人的规范表白规定,不是一种相似Java,C++的编程语言,而是一种剖析设计语言,一种建模语言1.3 UML构造UML构造通常包含以下4个局部:视图,图,模型元素以及通用机制。 1.3.1 视图UML视图用于从不同的角度来示意待建模的零碎。视图是由许多图形组成的一个形象汇合,在建设一个零碎模型时,只有通过定义多个视图,每个视图显示该零碎的一个特定方面,能力结构出该零碎的残缺蓝图。UML视图包含: 用户视图:以用户的观点示意零碎的指标,是所有视图的外围,用于形容零碎的需要构造视图:零碎的动态行为,形容零碎的动态元素,比方包,类,对象以及它们之间的关系行为视图:零碎的动静行为,形容零碎的组成元素在零碎运行时的交互关系实现视图:零碎中逻辑元素的散布,形容零碎中物理文件以及它们之间的关系环境视图:零碎中物理元素的散布,形容零碎中硬件设施以及他们之间的关系1.3.2 图UML图是形容UML视图内容的图形,UML2.0提供了13种图,别离是用例图,类图,对象图,包图,组合结构图,状态图,流动图,程序图,通信图,定时图,交互概览图,组件图和部署图。其中: 用例图对应用户视图类图,对象图,包图和组合结构图对应构造视图状态图,流动图,程序图,通信图,定时图和交互概览图对应行为视图组件图对应实现视图部署图对应环境视图1.3.3 模型元素模型元素是指UML图中所应用的一些概念,对应于一般的面向对象概念,如类,对象,音讯以及这些概念之间的关系,如关联关系,泛化关系等。 1.3.4 通用机制UML提供的通用机制为模型元素提供额定的正文,信息和语义,这些通用机制也提供了扩大机制,容许用户对UML进行扩大,如定义新的建模元素,扩大原有的语义,增加新的非凡信息来扩大模型元素的规定阐明等,以便实用于特定的办法或过程,组织和用户。 2 UML类图2.1 类图类封装了数据和行为,是具备雷同属性,操作,关系的对象汇合的总称。类图是用呈现在零碎中不同类来形容零碎的动态构造,次要形容不同的类以及它们之间的关系。在UML中,类图蕴含类名,属性以及操作。如上面的Employee类:类个别由三局部组成: 类名属性操作2.1.1 类名类名就是类的名字,一个字符串。 2.1.2 属性类的成员变量,个别的格局为 可见性 名称 : 类型 [ = 默认值]可见性示意该属性对于类外的元素是否可见,包含: 私有:+公有:-受爱护:#包:~2.1.3 操作UML规定操作的定义形式为: 可见性 名称(参数列表)[ : 返回类型]可见性与属性可见性的定义统一参数列表示意办法的参数,语法与属性定义相似,用,分隔2.2 类之间的关系UML提供了四种不同的形式示意类与类之间的关系: 关联关系依赖关系泛化关系接口与实现关系上面一一看一下。 3 关联关系关联关系是一种结构化关系,用于示意一类对象与另一类对象之间有分割。在UML中用实线连贯有关联关系的类。能够在关联线上标注角色名,关系的两端代表两种不同的角色,因而在一个关联关系中能够蕴含两个角色名,角色名不是必须的,但能够使类之间的关系更加明确。例如在一个登录界面类LoginForm蕴含一个JButton: UML中关联通常包含以下六种模式: 双向关联单向关联自关联多重性关联聚合关系组合关系3.1 双向关联默认状况下关联是双向的,例如顾客购买商品并领有商品,反之卖出的商品总是某个顾客与之相关联: 3.2 单向关联关联也能够是单向的,在UML中关联用带箭头的实线示意,比方顾客领有地址: 3.3 自关联零碎中可能会存在一些类的属性对象类型为该类自身,这种非凡的关联关系为自关联,常见于链表: 3.4 多重性关联多重性关联又称为多重性关联分割,示意两个关联对象在数量上的对应关系。在UML中,对象之间的多重性能够间接在关联直线上用一个数字或者一个数字范畴来示意。常见的示意形式如下:例如一个界面能够具备0个或多个按钮,然而一个按钮只能从属于一个界面: 3.5 聚合关系聚合关系示意整体与局部的关系,应用空心菱形示意。聚合关系中局部是整体的一部分,然而局部能够脱离整体独立存在,比方引擎是汽车的一部分,然而引擎能够独立于汽车存在: 3.6 组合关系组合关系也示意整体与局部之间的关系,然而局部不能脱离整体存在。组合关系应用实心菱形示意。比方人的头和嘴巴是组合关系: 4 依赖关系依赖关系是一种应用关系,在须要示意“一个事物应用另一个事物”时应用依赖关系。UML中依赖关系用带箭头的虚线示意,由依赖的一方指向被依赖的一方。例如驾驶员开车,开车须要车,也就是驾驶员依赖于车: 5 泛化关系泛化关系也就是继承关系,用于形容父类与之类之间的关系,父类又叫基类或者超类,子类又称作派生类。UML中泛化关系用带空心三角形的直线示意,箭头指向基类: 6 接口与实现关系很多语言比方Java,C#都有接口的概念,接口通常没有属性,所有是操作都是形象的,只有操作的申明没有操作的实现。UML中应用<<Interface>>示意接口:类与接口之间的实现关系应用空心三角形+虚线示意: 7 面向对象设计准则7.1 概述面向对象设计的指标之一是反对可维护性复用,一方面须要实现设计方案或者源代码的重用,一方面要确保零碎可能易于扩大和批改,具备较好的灵活性。面向对象设计准则由此诞生,它们蕴含于很多设计模式中,是从许多计划总结进去的指导性准则。常见的7种面向对象设计准则如下: 繁多权责准则开闭准则里氏代换准则依赖倒转准则接口隔离准则合成复用准则迪米特法令7.2 繁多职责准则SRP**繁多权责准则(Single Responsibility Principal):一个类只负责一个性能畛域中的相应职责。或者能够定义为:就一个类而言,应该只有一个引起它变动的起因。** ...

July 11, 2020 · 1 min · jiezi

设计模式9-门面模式

门面模式:如何设计正当的接口粒度以兼顾接口的易用性和通用性? 门面模式背景为了保障接口的可复用性(或者叫通用性),咱们须要将接口尽量设计得细粒度一点,职责繁多一点。然而,如果接口的粒度过小,在接口的使用者开发一个业务性能时,就会导致须要调用 n 多细粒度的接口能力实现。调用者必定会埋怨接口不好用。 相同,如果接口粒度设计得太大,一个接口返回 n 多数据,要做 n 多事件,就会导致接口不够通用、可复用性不好。接口不可复用,那针对不同的调用者的业务需要,咱们就须要开发不同的接口来满足,这就会导致系统的接口有限收缩。 那如何来解决接口的可复用性(通用性)和易用性之间的矛盾呢? --- 门面模式 门面模式的原理与实现门面模式,也叫外观模式,英文全称是 Facade Design Pattern。在 GoF 的《设计模式》一书中,门面模式是这样定义的: Provide a unified interface to a set of interfaces in a subsystem. Facade Pattern defines a higher-level interface that makes the subsystem easier to use.翻译成中文就是:门面模式为子系统提供一组对立的接口,定义一组高层接口让子系统更易用。 假如,实现某个业务性能(比方显示某个页面信息)须要“顺次”调用 a、b、d 三个接口,因本身业务的特点,不反对并发调用这三个接口。如果咱们当初发现 App 客户端的响应速度比较慢,排查之后发现,是因为过多的接口调用过多的网络通信。针对这种状况,咱们就能够利用门面模式,让后端服务器提供一个包裹 a、b、d 三个接口调用的接口 x。 App 客户端调用一次接口 x,来获取到所有想要的数据,将网络通信的次数从 3 次缩小到 1 次,也就进步了 App 的响应速度。

July 10, 2020 · 1 min · jiezi

设计模式8-适配器模式

适配器模式的英文翻译是 Adapter Design Pattern。顾名思义,这个模式就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让本来因为接口不兼容而不能一起工作的类能够一起工作。对于这个模式,有一个常常被拿来解释它的例子,就是 USB 转接头充当适配器,把两种不兼容的接口,通过转接变得能够一起工作。 适配器模式有两种实现形式:类适配器和对象适配器。 其中,类适配器应用继承关系来实现,对象适配器应用组合关系来实现。具体的代码实现如下所示。 // 类适配器: 基于继承public interface ITarget { void f1(); void f2(); void fc();}public class Adaptee { public void fa() { //... } public void fb() { //... } public void fc() { //... }}public class Adaptor extends Adaptee implements ITarget { public void f1() { super.fa(); } public void f2() { //...从新实现f2()... } // 这里fc()不须要实现,间接继承自Adaptee,这是跟对象适配器最大的不同点}**// **对象适配器:基于组合**public interface ITarget { void f1(); void f2(); void fc();}public class Adaptee { public void fa() { //... } public void fb() { //... } public void fc() { //... }}public class Adaptor implements ITarget { private Adaptee adaptee; public Adaptor(Adaptee adaptee) { this.adaptee = adaptee; } public void f1() { adaptee.fa(); //委托给Adaptee } public void f2() { //...从新实现f2()... } public void fc() { adaptee.fc(); }}适配器模式利用场景总结一般来说,适配器模式能够看作一种“弥补模式”,用来补救设计上的缺点。利用这种模式算是“无奈之举”。如果在设计初期,咱们就能协调躲避接口不兼容的问题,那这种模式就没有利用的机会了。 ...

July 9, 2020 · 2 min · jiezi

设计模式6-桥接模式

0. 回顾代理模式代理模式。它在不改变原始类(或者叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。代理模式在平时的开发经常被用到,常用在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志。1. 桥接模式(Bridge Design Pattern)1.1 定义1) GoF 的《设计模式》桥接模式是这么定义的:“Decouple an abstraction from its implementation so that the two can vary independently。”翻译成中文就是:“将抽象和实现解耦,让它们可以独立变化。” 2)另一种通俗理解:“一个类存在两个(或多个)独立变化的维度,我们通过组合的方式,让这两个(或多个)维度可以独立进行扩展。”通过组合关系来替代继承关系,避免继承层次的指数级爆炸。这种理解方式非常类似于,我“组合优于继承”设计原则。 > Think of composition as a has a relationship. A car "has an" engine, a person "has a" name, etc.> Think of inheritance as an is a relationship. A car "is a" vehicle, a person "is a" mammal, etc.上面两句话尽管没讲为什么组合更优秀,可是对于两者的差别却一针见血的说出来了。简单翻译一下,组合适用于,存在关系的类,就是说Class B仅仅须要Class A的某一个功能。继承则是属于关系,就是B extends A的话。那么B is A。属于关系。1.2 桥接模式 和 策略模式 区别桥接模式比策略模式更复杂,更具可塑性,可以说桥接模式中包含策略模式。 ...

July 7, 2020 · 1 min · jiezi

设计模式7-装饰器模式

待定 HeadFirst 补充

July 7, 2020 · 1 min · jiezi

设计模式6-代理模式

1. 代理模式在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。 2. 实现介绍2.1 类图 2.2 角色Subject: 抽象角色。声明真实对象和代理对象的共同接口。Proxy: 代理角色。代理对象与真实对象实现相同的接口,所以它能够在任何时刻都能够代理真实对象。代理角色内部包含有对真实对象的引用,所以她可以操作真实对象,同时也可以附加其他的操作,相当于对真实对象进行封装。- RealSubject: 真实角色。它代表着真实对象,是我们最终要引用的对象。3. 代码示例 --- 富士康生产手机假若你有一个工厂开始是生产手机的,但是它现在不想自己生产了,它把自己的东西交给了一家代工厂富士康去生产,那么便有了下面的代码去构建。统一的抽象接口 IFactoryclass IFactory{public: IFactory(){} virtual void makeProduct() = 0;};你的手机工厂class PhoneFactory : IFactory{public: PhoneFactory(){} void makeProduct() { cout<<"生产手机"<<endl; }};专门做代工的代理工厂富士康class FoxconnProxy : IFactory{public: FoxconnProxy(IFactory* factory) { m_real = factory; } void makeProduct() { m_real->makeProduct(); }private: IFactory* m_real;};3.1 客户端: IFactory* factory = new PhoneFactory(); FoxconnProxy* proxy = new FoxconnProxy(factory); proxy->makeProduct();3.2 说明    看了uml图和上面的代码你会可能会发现,先访问代理类再访问真正要访问的对象。 **似乎这样有点多此一举的味道,其实不然**。代理类可以在真正的类执行之前,进行预处理。 比富士康生产的手机之前可能会坚持元器件是否合格,不合格就不生产等。再比如你有一个系统实现了登陆功能,在用户登录时, 真正的登录类和代理登录类都实现了Login接口, 不同的是Proxy类的方法中增加了用户是否合法的判断, 只有合法时才去调用真正登录类的login方法. 用户访问的其实是Proxy的login方法.这都是代理模式的优点。而且采用代理模式的话,并且你可以随时更改代理。还有一点你会发现,真正对象与代理他们实现同一个接口。

July 7, 2020 · 1 min · jiezi

重学-Java-设计模式实战策略模式模拟多种营销类型优惠券折扣金额计算策略场景

作者:小傅哥博客:https://bugstack.cn - 原创系列专题文章 沉淀、分享、成长,让自己和他人都能有所收获!????一、前言文无第一,武无第二 不同方向但同样努力的人,都有自身的价值和亮点,也都是可以互相学习的。不要太过于用自己手里的矛去攻击别人的盾????,哪怕一时争辩过了也多半可能是你被安放的角色不同。取别人之强补自己之弱,矛与盾的结合可能就是坦克。 能把复杂的知识讲的简单很重要 在学习的过程中我们看过很多资料、视频、文档等,因为现在资料视频都较多所以往往一个知识点会有多种多样的视频形式讲解。除了推广营销以外,确实有很多人的视频讲解非常优秀,例如李永乐老师的短视频课,可以在一个黑板上把那么复杂的知识,讲解的那么容易理解,那么透彻。而我们学习编程的人也是,不只是要学会把知识点讲明白,也要写明白。 ????提升自己的眼界交往更多同好 有时候圈子很重要,就像上学期间大家都会发现班里有这样一类学生????????不怎么听课,但是就是学习好。那假如让他回家呆着,不能在课堂里呢?类似的圈子还有;图书馆、网吧、车友群、技术群等等,都可以给你带来同类爱好的人所分享出来的技能或者大家一起烘托出的氛围帮你成长。 二、开发环境JDK 1.8Idea + Maven涉及工程三个,可以通过关注公众号:bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)工程描述itstack-demo-design-20-01使用一坨代码实现业务需求itstack-demo-design-20-02通过设计模式优化改造代码,产生对比性从而学习三、策略模式介绍 策略模式是一种行为模式,也是替代大量ifelse的利器。它所能帮你解决的是场景,一般是具有同类可替代的行为逻辑算法场景。比如;不同类型的交易方式(信用卡、支付宝、微信)、生成唯一ID策略(UUID、DB自增、DB+Redis、雪花算法、Leaf算法)等,都可以使用策略模式进行行为包装,供给外部使用。 策略模式也有点像三国演义中诸葛亮给刘关张的锦囊; 第一个锦囊:见乔国老,并把刘备娶亲的事情du搞得东吴人尽皆知。第二个锦囊:用谎言(曹操打荆州)骗泡在温柔乡里的刘备回去。第三个锦囊:让孙夫人摆平东吴的追兵,她是孙权妹妹,东吴将领惧她三分。四、案例场景模拟 在本案例中我们模拟在购买商品时候使用的各种类型优惠券(满减、直减、折扣、n元购) 这个场景几乎也是大家的一个日常购物省钱渠道,购买商品的时候都希望找一些优惠券,让购买的商品更加实惠。而且到了大促的时候就会有更多的优惠券需要计算那些商品一起购买更加优惠!!! 这样的场景有时候用户用起来还是蛮爽的,但是最初这样功能的设定以及产品的不断迭代,对于程序员????????开发还是不太容易的。因为这里包括了很多的规则和优惠逻辑,所以我们模拟其中的一个计算优惠的方式,使用策略模式来实现。 五、用一坨坨代码实现这里我们先使用最粗暴的方式来实现功能 对于优惠券的设计最初可能非常简单,就是一个金额的抵扣,也没有现在这么多种类型。所以如果没有这样场景的经验话,往往设计上也是非常简单的。但随着产品功能的不断迭代,如果程序最初设计的不具备很好的扩展性,那么往后就会越来越混乱。 1. 工程结构itstack-demo-design-20-01└── src └── main └── java └── org.itstack.demo.design └── CouponDiscountService.java一坨坨工程的结构很简单,也是最直接的面向过程开发方式。2. 代码实现/** * 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获! * 公众号:bugstack虫洞栈 * Create by 小傅哥(fustack) @2020 * 优惠券折扣计算接口 * <p> * 优惠券类型; * 1. 直减券 * 2. 满减券 * 3. 折扣券 * 4. n元购 */public class CouponDiscountService { public double discountAmount(int type, double typeContent, double skuPrice, double typeExt) { // 1. 直减券 if (1 == type) { return skuPrice - typeContent; } // 2. 满减券 if (2 == type) { if (skuPrice < typeExt) return skuPrice; return skuPrice - typeContent; } // 3. 折扣券 if (3 == type) { return skuPrice * typeContent; } // 4. n元购 if (4 == type) { return typeContent; } return 0D; }}以上是不同类型的优惠券计算折扣后的实际金额。入参包括;优惠券类型、优惠券金额、商品金额,因为有些优惠券是满多少减少多少,所以增加了typeExt类型。这也是方法的不好扩展性问题。最后是整个的方法体中对优惠券抵扣金额的实现,最开始可能是一个最简单的优惠券,后面随着产品功能的增加,不断的扩展if语句。实际的代码可能要比这个多很多。六、策略模式重构代码接下来使用策略模式来进行代码优化,也算是一次很小的重构。 ...

July 6, 2020 · 3 min · jiezi

Aspnet-Core-31-Web-API添加jwt验证二用单例模式简单封装token生成器JwtGenerator

提出问题在上一篇我们搭建了一个基础的项目框架,并介绍了怎么向其中引入jwt鉴权,不知小伙伴们有没有注意到我们用于生成token的代码片段: [HttpGet("login")]public ActionResult Login(string username, string password){ if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password)) { // token中的claims用于储存自定义信息,如登录之后的用户id等 var claims = new[] { new Claim("userId", username) }; // 获取SecurityKey var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration.GetSection("Authentication")["SecurityKey"])); var token = new JwtSecurityToken( issuer: _configuration.GetSection("Authentication")["Issure"], // 发布者 audience: _configuration.GetSection("Authentication")["Audience"], // 接收者 notBefore: DateTime.Now, // token签发时间 expires: DateTime.Now.AddMinutes(30), // token过期时间 claims: claims, // 该token内存储的自定义字段信息 signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256) // 用于签发token的秘钥算法 ); // 返回成功信息,写出token return Ok(new { code = 200, message = "登录成功", data = new JwtSecurityTokenHandler().WriteToken(token) }); } // 返回错误请求信息 return BadRequest(new { code = 400, message = "登录失败,用户名或密码为空" });}在这段代码里,我们着重看下面这一段: ...

July 3, 2020 · 3 min · jiezi

重学-Java-设计模式实战状态模式模拟系统营销活动状态流程审核发布上线场景

作者:小傅哥博客:https://bugstack.cn - 原创系列专题文章 沉淀、分享、成长,让自己和他人都能有所收获!????一、前言写好代码三个关键点 如果把写代码想象成家里的软装,你肯定会想到家里需要有一个非常不错格局最好是南北通透的,买回来的家具最好是品牌保证质量的,之后呢是大小合适,不能摆放完了看着别扭。那么把这一过程抽象成写代码就是需要三个核心的关键点;架构(房间的格局)、命名(品牌和质量)、注释(尺寸大小说明书),只有这三个点都做好才能完成出一套赏心悦目的家。 平原走码????易放难收 上学期间你写了多少代码?上班一年你能写多少代码?回家自己学习写了多少代码?个人素养的技术栈地基都是一块一块砖码出来的,写的越广越深,根基就越牢固。当根基牢固了以后在再上层建设就变得迎刃而解了,也更容易建设了。往往最难的就是一层一层阶段的突破,突破就像破壳一样,也像夯实地基,短时间看不到成绩,也看不出高度。但以后谁能走的稳,就靠着默默的沉淀。 技术传承的重要性 可能是现在时间节奏太快,一个需求下来恨不得当天就上线(这个需求很简单,怎么实现我不管,明天上线!),导致团队的人都很慌、很急、很累、很崩溃,最终反反复复的人员更替,项目在这个过程中也交接了N次,文档不全、代码混乱、错综复杂,谁在后面接手也都只能修修补补,就像烂尾楼。这个没有传承、没有沉淀的项目,很难跟随业务的发展。最终!根基不牢,一地鸡毛。 二、开发环境JDK 1.8Idea + Maven涉及工程三个,可以通过关注公众号:bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)工程描述itstack-demo-design-19-00场景模拟工程;模拟营销活动操作服务(查询、审核)itstack-demo-design-19-01使用一坨代码实现业务需求itstack-demo-design-19-02通过设计模式优化改造代码,产生对比性从而学习三、状态模式介绍 状态模式描述的是一个行为下的多种状态变更,比如我们最常见的一个网站的页面,在你登录与不登录下展示的内容是略有差异的(不登录不能展示个人信息),而这种登录与不登录就是我们通过改变状态,而让整个行为发生了变化。 至少80后、90后的小伙伴基本都用过这种磁带放音机(可能没有这个好看),它的上面是一排按钮,当放入磁带后,通过上面的按钮就可以让放音机播放磁带上的内容(listen to 英语听力考试),而且有些按钮是互斥的,当在某个状态下才可以按另外的按钮(这在设计模式里也是一个关键的点)。 四、案例场景模拟 在本案例中我们模拟营销活动审核状态流转场景(一个活动的上线是多个层级审核上线的) 在上图中也可以看到我们的流程节点中包括了各个状态到下一个状态扭转的关联条件,比如;审核通过才能到活动中,而不能从编辑中直接到活动中,而这些状态的转变就是我们要完成的场景处理。 大部分程序员基本都开发过类似的业务场景,需要对活动或者一些配置需要审核后才能对外发布,而这个审核的过程往往会随着系统的重要程度而设立多级控制,来保证一个活动可以安全上线,避免造成资损。 当然有时候会用到一些审批流的过程配置,也是非常方便开发类似的流程的,也可以在配置中设定某个节点的审批人员。但这不是我们主要体现的点,在本案例中我们主要是模拟学习对一个活动的多个状态节点的审核控制。 1. 场景模拟工程itstack-demo-design-19-00└── src └── main └── java └── org.itstack.demo.design ├── ActivityInfo.java ├── Status.java └── ActivityService.java在这个模拟工程里我们提供了三个类,包括;状态枚举(Status)、活动对象(ActivityInfo)、活动服务(ActivityService),三个服务类。接下来我们就分别介绍三个类包括的内容。2. 代码实现2.1 基本活动信息public class ActivityInfo { private String activityId; // 活动ID private String activityName; // 活动名称 private Enum<Status> status; // 活动状态 private Date beginTime; // 开始时间 private Date endTime; // 结束时间 // ...get/set} 一些基本的活动信息;活动ID、活动名称、活动状态、开始时间、结束时间。2.2 活动枚举状态public enum Status { // 1创建编辑、2待审核、3审核通过(任务扫描成活动中)、4审核拒绝(可以撤审到编辑状态)、5活动中、6活动关闭、7活动开启(任务扫描成活动中) Editing, Check, Pass, Refuse, Doing, Close, Open}活动的枚举;1创建编辑、2待审核、3审核通过(任务扫描成活动中)、4审核拒绝(可以撤审到编辑状态)、5活动中、6活动关闭、7活动开启(任务扫描成活动中)2.3 活动服务接口public class ActivityService { private static Map<String, Enum<Status>> statusMap = new ConcurrentHashMap<String, Enum<Status>>(); public static void init(String activityId, Enum<Status> status) { // 模拟查询活动信息 ActivityInfo activityInfo = new ActivityInfo(); activityInfo.setActivityId(activityId); activityInfo.setActivityName("早起学习打卡领奖活动"); activityInfo.setStatus(status); activityInfo.setBeginTime(new Date()); activityInfo.setEndTime(new Date()); statusMap.put(activityId, status); } /** * 查询活动信息 * * @param activityId 活动ID * @return 查询结果 */ public static ActivityInfo queryActivityInfo(String activityId) { // 模拟查询活动信息 ActivityInfo activityInfo = new ActivityInfo(); activityInfo.setActivityId(activityId); activityInfo.setActivityName("早起学习打卡领奖活动"); activityInfo.setStatus(statusMap.get(activityId)); activityInfo.setBeginTime(new Date()); activityInfo.setEndTime(new Date()); return activityInfo; } /** * 查询活动状态 * * @param activityId 活动ID * @return 查询结果 */ public static Enum<Status> queryActivityStatus(String activityId) { return statusMap.get(activityId); } /** * 执行状态变更 * * @param activityId 活动ID * @param beforeStatus 变更前状态 * @param afterStatus 变更后状态 b */ public static synchronized void execStatus(String activityId, Enum<Status> beforeStatus, Enum<Status> afterStatus) { if (!beforeStatus.equals(statusMap.get(activityId))) return; statusMap.put(activityId, afterStatus); }}在这个静态类中提供了活动的查询和状态变更接口;queryActivityInfo、queryActivityStatus、execStatus。同时使用Map的结构来记录活动ID和状态变化信息,另外还有init方法来初始化活动数据。实际的开发中这类信息基本都是从数据库或者Redis中获取。五、用一坨坨代码实现这里我们先使用最粗暴的方式来实现功能 ...

July 3, 2020 · 6 min · jiezi

笔记设计模式5提高代码质量

策略模式/状态模式目的:优化if-else分支应用场景:当代码if-else分支过多时基本结构 // 计算器,将if判断用策略模式改写function calculator(type, a, b) { var strategy = { add(a, b) { return a + b }, minus(a, b) { return a - b }, division(a, b) { return a / b } } return strategy[type](a, b)}// 状态模式function stateFactor (state) { var stateObject = { _status: '', state: { state1 () {}, state2 () {} }, run () { return this.state[this._status]() } } stateObject._status = state return stateObject}stateFactor('state1').run()例:复合运动 ...

June 29, 2020 · 2 min · jiezi

笔记设计模式4提高可扩展性

提高可扩展性的目的面对需求变更,方便需求更改减少代码修改的难度什么是好的扩展需求的变更,不需要重写代码修改不会引起大规模变动方便加入新模块提高可扩展性的设计模式适配器模式(面向接口)目的:通过写一个适配器,来代替替换应用场景:接口不通用时基本结构 // 用log代替console.log 即调用的接口改变var log = (function() { return window.console.log})()例1:项目中本来用的A框架,现在要改成非常相似的jQuery框架,仅有部分接口名称不同 A.c() window.A = $ A.c = function () { return $.css.apply(this, arguments) }例2:当方法传入的参数较为复杂时,加上参数适配器,即默认值,用户传入的配置可以覆盖默认值 function fn (config) { let _default = { name: 1 } for (let k in config) { _default[k] = config[k] || _default[k] } }装饰者模式(面向方法)目的:不重写方法,但能实现扩展方法应用场景:当一个方法需要扩展,但是又不好直接去修改时基本结构 // 现有模块a,内部有方法b,不能直接修改方法b,但是需要扩展它var a = { b: function() {}}// 新建方法mybfunction myb () { // 先调用a.b a.b() // 再添加需要扩展的部分}例1 扩展已有的事件绑定 ...

June 29, 2020 · 4 min · jiezi

重学-Java-设计模式实战中介者模式按照Mybaits原理手写ORM框架给JDBC方式操作数据库增加中介者场景

作者:小傅哥博客:https://bugstack.cn - 原创系列专题文章 沉淀、分享、成长,让自己和他人都能有所收获!????一、前言同龄人的差距是从什么时候拉开的 同样的幼儿园、同样的小学、一样的书本、一样的课堂,有人学习好、有人学习差。不只是上学,几乎人生处处都是赛道,发令枪响起的时刻,也就把人生的差距拉开。编程开发这条路也是很长很宽,有人跑得快有人跑得慢。那么你是否想起过,这一点点的差距到遥不可及的距离,是从哪一天开始的。摸摸肚子的肉,看看远处的路,别人讲的是故事,你想起的都是事故。 思想没有产品高才写出一片的ifelse 当你承接一个需求的时候,比如;交易、订单、营销、保险等各类场景。如果你不熟悉这个场景下的业务模式,以及将来的拓展方向,那么很难设计出良好可扩展的系统。再加上产品功能初建,说老板要的急,尽快上线。作为程序员的你更没有时间思考,整体一看现在的需求也不难,直接上手开干(一个方法两个if语句),这样确实满足了当前需求。但老板的想法多呀,产品也跟着变化快,到你这就是改改改,加加加。当然你也不客气,回首掏就是1024个if语句! 日积月累的技术沉淀是为了厚积薄发 粗略的估算过,如果从上大学开始每天写200行,一个月是6000行,一年算10个月话,就是6万行,第三年出去实习的是时候就有20万行的代码量。如果你能做到这一点,找工作难?有时候很多事情就是靠时间积累出来的,想走捷径有时候真的没有。你的技术水平、你的业务能力、你身上的肉,都是一点点积累下来的,不要浪费看似很短的时间,一年年坚持下来,留下印刻青春的痕迹,多给自己武装上一些能力。 二、开发环境JDK 1.8Idea + Mavenmysql 5.1.20涉及工程一个,可以通过关注公众号:bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)工程描述itstack-demo-design-16-01使用JDBC方式连接数据库itstack-demo-design-16-02手写ORM框架操作数据库三、中介者模式介绍 中介者模式要解决的就是复杂功能应用之间的重复调用,在这中间添加一层中介者包装服务,对外提供简单、通用、易扩展的服务能力。 这样的设计模式几乎在我们日常生活和实际业务开发中都会见到,例如;飞机????降落有小姐姐在塔台喊话、无论哪个方向来的候车都从站台上下、公司的系统中有一个中台专门为你包装所有接口和提供统一的服务等等,这些都运用了中介者模式。除此之外,你用到的一些中间件,他们包装了底层多种数据库的差异化,提供非常简单的方式进行使用。 四、案例场景模拟 在本案例中我们通过模仿Mybatis手写ORM框架,通过这样操作数据库学习中介者运用场景 除了这样的中间件层使用场景外,对于一些外部接口,例如N种奖品服务,可以由中台系统进行统一包装对外提供服务能力。也是中介者模式的一种思想体现。 在本案例中我们会把jdbc层进行包装,让用户在使用数据库服务的时候,可以和使用mybatis一样简单方便,通过这样的源码方式学习中介者模式,也方便对源码知识的拓展学习,增强知识栈。 五、用一坨坨代码实现这是一种关于数据库操作最初的方式 基本上每一个学习开发的人都学习过直接使用jdbc方式连接数据库,进行CRUD操作。以下的例子可以当做回忆。 1. 工程结构itstack-demo-design-16-01└── src └── main └── java └── org.itstack.demo.design └── JDBCUtil.java这里的类比较简单只包括了一个数据库操作类。2. 代码实现public class JDBCUtil { private static Logger logger = LoggerFactory.getLogger(JDBCUtil.class); public static final String URL = "jdbc:mysql://127.0.0.1:3306/itstack-demo-design"; public static final String USER = "root"; public static final String PASSWORD = "123456"; public static void main(String[] args) throws Exception { //1. 加载驱动程序 Class.forName("com.mysql.jdbc.Driver"); //2. 获得数据库连接 Connection conn = DriverManager.getConnection(URL, USER, PASSWORD); //3. 操作数据库 Statement stmt = conn.createStatement(); ResultSet resultSet = stmt.executeQuery("SELECT id, name, age, createTime, updateTime FROM user"); //4. 如果有数据 resultSet.next() 返回true while (resultSet.next()) { logger.info("测试结果 姓名:{} 年龄:{}", resultSet.getString("name"),resultSet.getInt("age")); } }}以上是使用JDBC的方式进行直接操作数据库,几乎大家都使用过这样的方式。3. 测试结果15:38:10.919 [main] INFO org.itstack.demo.design.JDBCUtil - 测试结果 姓名:水水 年龄:1815:38:10.922 [main] INFO org.itstack.demo.design.JDBCUtil - 测试结果 姓名:豆豆 年龄:1815:38:10.922 [main] INFO org.itstack.demo.design.JDBCUtil - 测试结果 姓名:花花 年龄:19Process finished with exit code 0从测试结果可以看到这里已经查询到了数据库中的数据。只不过如果在全部的业务开发中都这样实现,会非常的麻烦。六、中介模式开发ORM框架`接下来就使用中介模式的思想完成模仿Mybatis的ORM框架开发~ ...

June 28, 2020 · 7 min · jiezi

设计模式-介绍

设计模式的类型根据《设计模式》参考书,共有 23 种设计模式,这些模式可以分为三类: 类型描述创建型模式(Creational Patterns)用于构建对象,以便它们可以从实现系统中分离出来。结构型模式(Structural Patterns)用于在许多不同的对象之间形成大型对象结构。行为型模式(Behavioral Patterns)用于管理对象之间的算法、关系和职责。创建型模式单例模式(Singleton Pattern)保证一个类仅有一个实例,并提供一个访问它的全局访问点。工厂模式 (Factory Pattern) 工厂方法模式 (Factory Method Pattern)定义一个用于创建对象的接口,让子类决定将哪一个类实例化。Factory Method 使一个类的实例化延迟到其子类。抽象工厂模式 (Abstract Factory Pattern)提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。建造者模式(Builder Pattern)将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。原型模式(Prototype Pattern)用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。ReferenceC++ 设计模式

June 27, 2020 · 1 min · jiezi

设计模式5-原型模式

原型模式的应用场景,以及它的两种实现方式:深拷贝和浅拷贝。 1. 原型模式 (Prototype Design Pattern)如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的。 这种基于原型来创建对象的方式就叫作原型设计模式(Prototype Design Pattern),简称原型模式。 1.1 对象的创建成本比较大?创建对象:申请内存、给成员变量赋值这一过程,一般情况下,这一过程耗费时间不大。 但某些情况下,创建对象给对象赋值时,可能需要从IO设备中读取数据,比如:数据库 / 文件 等。 再之,对 对象进行排序、计算哈希值,这种情况下,可能就比较耗时了。 在这种情况下,原型模式,便可以派上用场了。 1.2 深拷贝和浅拷贝在原型模式中,需要特别注意的是,深拷贝和浅拷贝。 因为不同的场景,这两种拷贝方式,会带来不一样的结果。 浅拷贝只会复制对象中基本数据类型数据和引用对象的内存地址,不会递归地复制引用对象,以及引用对象的引用对象…… 深拷贝得到的是一份完完全全独立的对象。所以,深拷贝比起浅拷贝来说,更加耗时,更加耗内存空间。 如果要拷贝的对象是不可变对象,浅拷贝共享不可变对象是没问题的。 但对于可变对象来说,浅拷贝得到的对象和原始对象会共享部分数据,就有可能出现数据被修改的风险,也就变得复杂多了。除非像我们今天实战中举的那个例子,需要从数据库中加载 10 万条数据并构建散列表索引,操作非常耗时,比较推荐使用浅拷贝,否则,没有充分的理由,不要为了一点点的性能提升而使用深拷贝。

June 27, 2020 · 1 min · jiezi

设计模式4-建造者模式

Builder 模式,中文翻译为建造者模式或者构建者模式,也有人叫它生成器模式。1. 定义定义虽然基本没有。。用,因为大部分人都看不懂,但是还的说出来。。。 The intent of the Builder design pattern is to separate the construction of a complex object from its representation. By doing so the same construction process can create different representations.将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。 2. 介绍2.1 使用场景当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。 2.2 为了解决什么问题?当一个类的构造函数参数超过4个,而且这些参数有些是可选的时,我们通常有两种办法来构建它的对象。 例如我们现在有如下一个类计算机类Computer,其中cpu与ram是必填参数,而其他3个是可选参数,那么我们如何构造这个类的实例呢,通常有两种常用的方式: public class Computer { private String cpu;//必须 private String ram;//必须 private int usbCount;//可选 private String keyboard;//可选 private String display;//可选}第一:折叠构造函数模式(telescoping constructor pattern ),这个我们经常用,如下代码所示 public class Computer { ... public Computer(String cpu, String ram) { this(cpu, ram, 0); } public Computer(String cpu, String ram, int usbCount) { this(cpu, ram, usbCount, "罗技键盘"); } public Computer(String cpu, String ram, int usbCount, String keyboard) { this(cpu, ram, usbCount, keyboard, "三星显示器"); } public Computer(String cpu, String ram, int usbCount, String keyboard, String display) { this.cpu = cpu; this.ram = ram; this.usbCount = usbCount; this.keyboard = keyboard; this.display = display; }}第二种:Javabean 模式,如下所示 ...

June 26, 2020 · 2 min · jiezi

设计模式3-工厂模式

工厂模式(Factory Design Pattern)分类:简单工厂、工厂方法和抽象工厂。 之所以将某个代码块剥离出来,独立为函数或者类,原因是这个代码块的逻辑过于复杂,剥离之后能让代码更加清晰,更加可读、可维护。应用场景:什么时候该用工厂模式?相对于直接 new 来创建对象,用工厂模式来创建究竟有什么好处呢?1. 简单工厂Code 如下: public class RuleConfigSource { public RuleConfig load(String ruleConfigFilePath) { String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath); IRuleConfigParser parser = RuleConfigParserFactory.createParser(ruleConfigFileExtension); if (parser == null) { 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"; }}public class RuleConfigParserFactory { public static IRuleConfigParser createParser(String configFormat) { IRuleConfigParser parser = null; if ("json".equalsIgnoreCase(configFormat)) { parser = new JsonRuleConfigParser(); } else if ("xml".equalsIgnoreCase(configFormat)) { parser = new XmlRuleConfigParser(); } else if ("yaml".equalsIgnoreCase(configFormat)) { parser = new YamlRuleConfigParser(); } else if ("properties".equalsIgnoreCase(configFormat)) { parser = new PropertiesRuleConfigParser(); } return parser; }}2. 工厂方法(Factory Method)如果我们非得要将 if 分支逻辑去掉,那该怎么办呢?比较经典处理方法就是利用多态。 ...

June 26, 2020 · 3 min · jiezi

设计模式2-单例模式

为什么要使用单例?单例存在哪些问题?单例与静态类的区别?有何替代的解决方案? 1. 命令模式介绍1.1 定义单例设计模式(Singleton Design Pattern): 一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。 命令模式的本质:封装请求设计意图:命令模式通过将请求封装到一个命令(Command)对象中,实现了请求调用者和具体实现者之间的解耦。1.2 应用场景为什么要使用单例?单例存在哪些问题?单例与静态类的区别?有何替代的解决方案? 2. 示例2.1 实战案例一:处理资源访问冲突代码如下: public class Logger { private FileWriter writer; public Logger() { File file = new File("/Users/wangzheng/log.txt"); writer = new FileWriter(file, true); //true表示追加写入 } public void log(String message) { writer.write(mesasge); }}// Logger类的应用示例: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()); }}如上日志打印代码,势必会导致文件覆盖。如果加对象锁,占用内存等;单例模式相对于之前类级别锁的好处是,不用创建那么多 Logger 对象,一方面节省内存空间,另一方面节省系统文件句柄(对于操作系统来说,文件句柄也是一种资源,不能随便浪费)。2.2 实战案例二:表示全局唯一类从业务概念上,如果有些数据在系统中只应保存一份,那就比较适合设计为单例类。比如,配置信息类。在系统中,我们只有一个配置文件,当配置文件被加载到内存之后,以对象的形式存在,也理所应当只有一份。3. 单例模式实现实现单例模式,需要注意的点: ...

June 26, 2020 · 2 min · jiezi

重学-Java-设计模式实战迭代器模式模拟公司组织架构树结构关系深度迭代遍历人员信息输出场景

作者:小傅哥博客:https://bugstack.cn - 原创系列专题文章 沉淀、分享、成长,让自己和他人都能有所收获!????一、前言相信相信的力量! 从懵懂的少年,到拿起键盘,可以写一个HelloWorld。多数人在这并不会感觉有多难,也不会认为做不出来。因为这样的例子,有老师的指导、有书本的例子、有前人的经验。但随着你的开发时间越来越长,要解决更复杂的问题或者技术创新,因此在网上搜了几天几夜都没有答案,这个时候是否想过放弃,还是一直坚持不断的尝试一点点完成自己心里要的结果。往往这种没有前车之鉴需要自己解决问题的时候,可能真的会折磨到要崩溃,但你要愿意执着、愿意倔强,愿意选择相信相信的力量,就一定能解决。哪怕解决不了,也可以在这条路上摸索出其他更多的收获,为后续前进的道路填充好垫脚石。 时间紧是写垃圾代码的理由? 拧螺丝?Ctrl+C、Ctrl+V?贴膏药一样写代码?没有办法,没有时间,往往真的是借口,胸中没用笔墨,才只能凑合。难道一定是好好写代码就浪费时间,拼凑CRUD就快吗,根本不可能的。因为不会,没用实操过,很少架构出全场景的设计,才很难写出优良的代码。多增强自身的编码(武术)修为,在各种编码场景中让自己变得老练,才好应对紧急情况下的需求开发和人员安排。就像韩信一样有谋有略,才能执掌百万雄兵。 不要只是做个工具人! 因为日常的编写简单业务需求,导致自己像个工具人一样,日久天长的也就很少去深入学习更多技术栈。看见有工具、有组件、有框架,拿来就用用,反正没什么体量也不会出什么问题。但如果你想要更多的收入,哪怕是重复的造轮子,你也要去尝试造一个,就算不用到生产,自己玩玩总可以吧。有些事情只有自己经历过,才能有最深的感触,参与过实践过,才好总结点评学习。 二、开发环境JDK 1.8Idea + Maven涉及工程一个,可以通过关注公众号:bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)工程描述itstack-demo-design-15-00开发树形组织架构关系迭代器三、迭代器模式介绍 迭代器模式,常见的就是我们日常使用的iterator遍历。虽然这个设计模式在我们的实际业务开发中的场景并不多,但却几乎每天都要使用jdk为我们提供的list集合遍历。另外增强的for循环虽然是循环输出数据,但是他不是迭代器模式。迭代器模式的特点是实现Iterable接口,通过next的方式获取集合元素,同时具备对元素的删除等操作。而增强的for循环是不可以的。 这种设计模式的优点是可以让我们以相同的方式,遍历不同的数据结构元素,这些数据结构包括;数组、链表、树等,而用户在使用遍历的时候并不需要去关心每一种数据结构的遍历处理逻辑,从让使用变得统一易用。 四、案例场景模拟 在本案例中我们模拟迭代遍历输出公司中树形结构的组织架构关系中雇员列表 大部分公司的组织架构都是金字塔结构,也就这种树形结构,分为一级、二级、三级等部门,每个组织部门由雇员填充,最终体现出一个整体的树形组织架构关系。 一般我们常用的遍历就是jdk默认提供的方法,对list集合遍历。但是对于这样的偏业务特性较大的树形结构,如果需要使用到遍历,那么就可以自己来实现。接下来我们会把这个组织层次关系通过树形数据结构来实现,并完成迭代器功能。 五、迭代器模式遍历组织结构在实现迭代器模式之前可以先阅读下java中list方法关于iterator的实现部分,几乎所有的迭代器开发都会按照这个模式来实现,这个模式主要分为以下几块; Collection,集合方法部分用于对自定义的数据结构添加通用方法;add、remove、iterator等核心方法。Iterable,提供获取迭代器,这个接口类会被Collection继承。Iterator,提供了两个方法的定义;hasNext、next,会在具体的数据结构中写实现方式。除了这样通用的迭代器实现方式外,我们的组织关系结构树,是由节点和节点间的关系链构成,所以会比上述的内容多一些入参。 1. 工程结构itstack-demo-design-15-02└── src ├── main │ └── java │ └── org.itstack.demo.design │ ├── group │ │ ├── Employee.java │ │ ├── GroupStructure.java │ │ └── Link.java │ └── lang │ ├── Collection.java │ ├── Iterable.java │ └── Iterator.java └── test └── java └── org.itstack.demo.design.test └── ApiTest.java迭代器模式模型结构 ...

June 24, 2020 · 3 min · jiezi

设计模式1-命令模式

1. 命令模式介绍1.1 定义命令模式的英文翻译是 Command Design Pattern。在 GoF 的《设计模式》一书中,它是这么定义的: The command pattern encapsulates a request as an object, thereby letting us parameterize other objects with different requests, queue or log requests, and support undoable operations.中文翻译为:命令模式:将请求封装成对象,以便使用不同的请求、日志、队列等来参数化其他对象。命令模式也支持撤销操作。 命令模式的本质:封装请求设计意图:命令模式通过将请求封装到一个命令(Command)对象中,实现了请求调用者和具体实现者之间的解耦。1.2 应用场景在需要事务的系统中,可以选用命令模式。命令模式提供了对事务进行建模的方法。命令模式有一个别名就是Transaction。命令模式,类似于C语言里的回调函数。 1.3 命令模式的结构命令模式涉及的角色及其职责如下: 抽象命令(Command):一般定义为接口,用来定义执行命令的接口。具体命令(ConcreteCommand)角色:通常会持有接收者对象,并调用接收者对象的相应功能来完成命令要执行的操作。接收者(Receiver)角色:真正执行命令的对象。任何类都可能成为接收者,只要它能够实现命令要求实现的相应功能。调用者(Invoker)角色:要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。客户端(Client)角色:创建具体的命令对象,并且设置命令对象的接收者。2. 示例代码以客人点餐为例,实现:点餐和cook隔离。 // CommandModel.h文件#pragma once#include <iostream>#include <vector>#include <algorithm>// 烤肉师傅class BarbecueMaster{public: void MakeMutton() { std::cout << "烤羊腿喽" << std::endl; } void MakeChiken() { std::cout << "烤鸡肉喽" << std::endl; }};// 命令类class Command{protected: BarbecueMaster * m_master;public: Command(BarbecueMaster * p) { m_master = p; } virtual void executeCmd() = 0;};// 命令1class CommandMutton : public Command{public: CommandMutton(BarbecueMaster * p) : Command(p) {} void executeCmd() { m_master->MakeMutton(); }};// 命令2class CommandChiken : public Command{public: CommandChiken(BarbecueMaster * p) : Command(p) {} void executeCmd() { m_master->MakeChiken(); }};// 服务员class Waiter{private: std::vector<Command *> m_vec;public: ~Waiter() { for (auto it = m_vec.begin(); it != m_vec.end(); it++) { delete(*it); } m_vec.clear(); } // Waiter Func1 void add(Command * p) { m_vec.push_back(p); } // Waiter Func2 void remove(Command * p) { auto it = find(m_vec.begin(), m_vec.end(), p); if (it != m_vec.end()) m_vec.erase(it); } // Waiter Func3 void submitCmd() { for (auto it = m_vec.cbegin(); it != m_vec.cend(); it++) { (*it)->executeCmd(); } }};测试代码: ...

June 23, 2020 · 2 min · jiezi

设计模式之观察者模式

定义定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 观察者模式的UML类图及说明如上图(图片来源于《head_first设计模式》)所示,观察者的uml中主要有以下类1.主题Subject(接口)Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法,主要为观察者注册方法(registerObserver),观察者删除方法(removeObserver),通知观察者方法(notifyObservers)2.观察者Observer(接口)Observer观察者一般是一个接口,每一个实现该接口的实现类都是具体观察者。主要提供一个update方法。3.具体主题ConcreteSubject(Subject的具体实现)是对主题Subject接口的具体实现,该类可根据具体业务扩展4.具体观察者ConcreteObserver(Observer的具体实现)是对Observer观察者的具体实现,一般订阅者会有多个,所以该类可通过自己需要的消息进行扩展 观察者模式的优缺点及应用场景优点:1.观察者和被观察者是抽象耦合的。2.建立一套触发机制。缺点:1.如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。2.如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。3.观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。应用场景:1.关联行为场景2.事件多级触发场景4.跨系统的消息变换场景,如消息队列的处理机制应用实例:1.新闻的发布订阅2.天气信息的发布订阅 注意事项:1、JAVA 中已经有了对观察者模式的支持类。2、避免循环引用。3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。 Spring中的观察者模式1.事件(ApplicationEvent)ApplicationEvent 是所有事件对象的父类。ApplicationEvent 继承自 jdk 的 EventObject, 所有的事件都需要继承 ApplicationEvent, 并且通过source得到事件源。 2.事件监听(ApplicationListener)ApplicationListener 事件监听器,也就是观察者。继承自 jdk 的 EventListener,该类中只有一个方法 onApplicationEvent。当监听的事件发生后该方法会被执行。 3.事件发布(ApplicationContext)ApplicationContext 是 Spring 中的核心容器,在事件监听中 ApplicationContext 可以作为事件的发布者,也就是事件源。因为 ApplicationContext 继承自 ApplicationEventPublisher。在 ApplicationEventPublisher 中定义了事件发布的方法 — publishEvent(Object event) 4.事件管理(ApplicationEventMulticaster)ApplicationEventMulticaster 用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把 Applicationcontext 发布的 Event 广播给它的监听器列表。 观察者模式的实现现在的线上直播模式非常的火,在这里,以简单的LOL比赛信息订阅为例。比如我们要关注今天有哪些了LPL的比赛信息,后几天有哪些比赛信息,我们就可以点击订阅,订阅后,有新的比赛信息,就会推送给你。 这样的场景下,我们就可以用观察者模式来实现: 定义主题接口 /** * 主题接口,对象通过此接口注册为观察者,或者把自己从观察者中删除 * * @author yyl */public interface Subject { /** * 观察者注册 * */ void registerObserver(Observer observer); /** * 删除观察者 * */ void removeObserver(Observer observer); /** * 通知观察者 * */ void notifyObservers();}定义主题接口的具体实现,及LOL比赛信息主题 ...

June 22, 2020 · 2 min · jiezi

重学-Java-设计模式实战命令模式模拟高档餐厅八大菜系小二点单厨师烹饪场景

作者:小傅哥博客:https://bugstack.cn - 原创系列专题文章 沉淀、分享、成长,让自己和他人都能有所收获!????一、前言持之以恒的重要性 初学编程往往都很懵,几乎在学习的过程中会遇到各种各样的问题,哪怕别人那运行好好的代码,但你照着写完就报错。但好在你坚持住了,否则你可能看不到这篇文章。时间和成长就是相互关联着,你在哪条路上坚持走的久,就能看见那条的终点有多美,但如果你浪费了一次又一次努力的机会,那么你也会同样错过很多机遇,因为你的路换了。坚持学习、努力成长,持以恒的付出一定会有所收获。 学习方法的重要性 不会学习往往会耽误很多时间,又没有可观的收成。但不会学习有时候是因为懒造成的,尤其是学习视频、书籍资料、技术文档等,如果只是看了却不是实际操作验证,那么真的很难把别人的知识让自己吸收,即使是当时感觉会了也很快就会忘记。时而也经常会有人找到你说;“这个我不知道,你先告诉我,过后我就学。”但过后你学了吗? 你愿意为一个知识盲区付出多长时间 你心里时而会蹦出这样的词吗;太难了我不会、找个人帮一下吧、放弃了放弃了,其实谁都可能遇到很不好解决的问题,也是可以去问去咨询的。但,如果在这之前你没有在自己的大脑中反复的寻找答案,那么你的大脑中就不会形成一个凸点的知识树,缺少了这个学习过程也就缺少了查阅各种资料给自己大脑填充知识的机会,哪怕是问到了答案最终也会因时间流逝而忘记。 二、开发环境JDK 1.8Idea + Maven涉及工程三个,可以通过关注公众号:bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)工程描述itstack-demo-design-14-01使用一坨代码实现业务需求itstack-demo-design-14-02通过设计模式优化代码结构,增加扩展性和维护性三、命令模式介绍 命令模式在我们通常的互联网开发中相对来说用的比较少,但这样的模式在我们的日常中却经常使用到,那就是Ctrl+C、Ctrl+V。当然如果你开发过一些桌面应用,也会感受到这样设计模式的应用场景。从这样的模式感受上,可以想到这是把逻辑实现与操作请求进行分离,降低耦合方便扩展。 命令模式是行为模式中的一种,以数据驱动的方式将命令对象,可以使用构造函数的方式传递给调用者。调用者再提供相应的实现为命令执行提供操作方法。可能会感觉这部分有一些饶,可以通过对代码的实现进行理解,在通过实操来熟练。 在这个设计模式的实现过程中有如下几个比较重要的点; 抽象命令类;声明执行命令的接口和方法具体的命令实现类;接口类的具体实现,可以是一组相似的行为逻辑实现者;也就是为命令做实现的具体实现类调用者;处理命令、实现的具体操作者,负责对外提供命令服务四、案例场景模拟 在这个案例中我们模拟在餐厅中点餐交给厨师????????烹饪的场景 命令场景的核心的逻辑是调用方与不需要去关心具体的逻辑实现,在这个场景中也就是点餐人员只需要把需要点的各种菜系交个小二就可以,小二再把各项菜品交给各个厨师进行烹饪。也就是点餐人员不需要跟各个厨师交流,只需要在统一的环境里下达命令就可以。 在这个场景中可以看到有不同的菜品;山东(鲁菜)、四川(川菜)、江苏(苏菜)、广东(粤菜)、福建(闽菜)、浙江(浙菜)、湖南(湘菜),每种菜品都会有不同的厨师????????进行烹饪。而客户并不会去关心具体是谁烹饪,厨师也不会去关心谁点的餐。客户只关心早点上菜,厨师只关心还有多少个菜要做。而这中间的衔接的过程,由小二完成。 那么在这样的一个模拟场景下,可以先思考????哪部分是命令模式的拆解,哪部分是命令的调用者以及命令的实现逻辑。 五、用一坨坨代码实现不考虑设计模式的情况下,在做这样一个点单系统,有一个类就够了 像是这样一个复杂的场景,如果不知道设计模式直接开发,也是可以达到目的的。但对于后续的各项的菜品扩展、厨师实现以及如何调用上会变得非常耦合难以扩展。 1. 工程结构itstack-demo-design-14-01└── src └── main └── java └── org.itstack.demo.design └── XiaoEr.java这里只有一个饭店小二的类,通过这样的一个类实现整个不同菜品的点单逻辑。2. 代码实现public class XiaoEr { private Logger logger = LoggerFactory.getLogger(XiaoEr.class); private Map<Integer, String> cuisineMap = new ConcurrentHashMap<Integer, String>(); public void order(int cuisine) { // 广东(粤菜) if (1 == cuisine) { cuisineMap.put(1, "广东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头"); } // 江苏(苏菜) if (2 == cuisine) { cuisineMap.put(2, "江苏厨师,烹饪苏菜,宫廷第二大菜系,古今国宴上最受人欢迎的菜系。"); } // 山东(鲁菜) if (3 == cuisine) { cuisineMap.put(3, "山东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头."); } // 四川(川菜) if (4 == cuisine) { cuisineMap.put(4, "四川厨师,烹饪川菜,中国最有特色的菜系,也是民间最大菜系。"); } } public void placeOrder() { logger.info("菜单:{}", JSON.toJSONString(cuisineMap)); }}在这个类的实现中提供了两个方法,一个方法用于点单添加菜品order(),另外一个方法展示菜品的信息placeOrder()。从上面可以看到有比较多的if语句判断类型进行添加菜品,那么对于这样的代码后续就需要大量的经历进行维护,同时可能实际的逻辑要比这复杂的多。都写在这样一个类里会变得耦合的非常严重。六、命令模式重构代码接下来使用命令模式来进行代码优化,也算是一次很小的重构。 ...

June 22, 2020 · 3 min · jiezi

设计模式对象池模式

今天我们来介绍一下对象池模式,这种设计模式在平时的工作中使用频率不像工厂模式那样使用频繁,但是它提供了一种新的对象使用和管理思想,还是很值得借鉴的。 既然提到池了,那就是某一类或者一种事物的集合,比如线程池,这里面会涉及到把对象放到池子和从池子里面取对象的过程。 那我们先来定义一个Art类: class Art{ private $_name; /** * @return mixed */ public function getName() { return $this->_name; } /** * @param mixed $name */ public function setName($name) { $this->_name = $name; }}我们还需要定义一个对象池(ArtPool),来处理Art的入池和出池操作: class ArtPool{ //艺术类列表 static private $_arts = []; /** * 对象池中加入对象 * * @param Art $art */ static public function pushArt(Art $art) { if(!isset(static::$_arts[$art->getName()]) || empty(static::$_arts[$art->getName()])) { static::$_arts[$art->getName()] = $art; } } /** * 获取对象 * * @param $name * @return mixed|null */ public static function getArt($name) { return isset(self::$_arts[$name]) ? self::$_arts[$name] : null; } /** * 从对象池中删除对象 * * @param $name */ public static function removeArt($name) { if(array_key_exists($name, self::$_arts)) { unset(self::$_arts[$name]); } }}这里面有个比较重要的地方需要注意一下,就是: ...

June 17, 2020 · 1 min · jiezi

重学-Java-设计模式实战装饰器模式SSO单点登录功能扩展增加拦截用户访问方法范围场景

作者:小傅哥博客:https://bugstack.cn 沉淀、分享、成长,让自己和他人都能有所收获!?一、前言对于代码你有编程感觉吗 很多人写代码往往是没有编程感觉的,也就是除了可以把功能按照固定的流程编写出流水式的代码外,很难去思考整套功能服务的扩展性和可维护性。尤其是在一些较大型的功能搭建上,比较缺失一些驾驭能力,从而导致最终的代码相对来说不能做到尽善尽美。 江洋大盗与江洋大偷 两个本想描述一样的意思的词,只因一字只差就让人觉得一个是好牛,一个好搞笑。往往我们去开发编程写代码时也经常将一些不恰当的用法用于业务需求实现中,当却不能意识到。一方面是由于编码不多缺少较大型项目的实践,另一方面是不思进取的总在以完成需求为目标缺少精益求精的工匠精神。 书从来不是看的而是用的 在这个学习资料几乎爆炸的时代,甚至你可以轻易就获取几个T的视频,小手轻轻一点就收藏一堆文章,但却很少去看。学习的过程从不只是简单的看一遍就可以,对于一些实操性的技术书籍,如果真的希望学习到知识,那么一定是把这本书用起来而绝对不是看起来。 二、开发环境JDK 1.8Idea + Maven涉及工程三个,可以通过关注公众号:bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)工程描述itstack-demo-design-9-00场景模拟工程;模拟单点登录类itstack-demo-design-9-01使用一坨代码实现业务需求itstack-demo-design-9-02通过设计模式优化改造代码,产生对比性从而学习三、装饰器模式介绍 初看上图感觉装饰器模式有点像俄罗斯套娃、某众汽车?,而装饰器的核心就是再不改原有类的基础上给类新增功能。不改变原有类,可能有的小伙伴会想到继承、AOP切面,当然这些方式都可以实现,但是使用装饰器模式会是另外一种思路更为灵活,可以避免继承导致的子类过多,也可以避免AOP带来的复杂性。 你熟悉的场景很多用到装饰器模式 new BufferedReader(new FileReader(""));,这段代码你是否熟悉,相信学习java开发到字节流、字符流、文件流的内容时都见到了这样的代码,一层嵌套一层,一层嵌套一层,字节流转字符流等等,而这样方式的使用就是装饰器模式的一种体现。 四、案例场景模拟 在本案例中我们模拟一个单点登录功能扩充的场景 一般在业务开发的初期,往往内部的ERP使用只需要判断账户验证即可,验证通过后即可访问ERP的所有资源。但随着业务的不断发展,团队里开始出现专门的运营人员、营销人员、数据人员,每个人员对于ERP的使用需求不同,有些需要创建活动,有些只是查看数据。同时为了保证数据的安全性,不会让每个用户都有最高的权限。 那么以往使用的SSO是一个组件化通用的服务,不能在里面添加需要的用户访问验证功能。这个时候我们就可以使用装饰器模式,扩充原有的单点登录服务。但同时也保证原有功能不受破坏,可以继续使用。 1. 场景模拟工程itstack-demo-design-9-00└── src └── main └── java └── org.itstack.demo.design ├── HandlerInterceptor.java └── SsoInterceptor.java这里模拟的是spring中的类:HandlerInterceptor,实现起接口功能SsoInterceptor模拟的单点登录拦截服务。为了避免引入太多spring的内容影响对设计模式的阅读,这里使用了同名的类和方法,尽可能减少外部的依赖。2. 场景简述2.1 模拟Spring的HandlerInterceptorpublic interface HandlerInterceptor { boolean preHandle(String request, String response, Object handler);}实际的单点登录开发会基于;org.springframework.web.servlet.HandlerInterceptor 实现。2.2 模拟单点登录功能public class SsoInterceptor implements HandlerInterceptor{ public boolean preHandle(String request, String response, Object handler) { // 模拟获取cookie String ticket = request.substring(1, 8); // 模拟校验 return ticket.equals("success"); }}这里的模拟实现非常简单只是截取字符串,实际使用需要从HttpServletRequest request对象中获取cookie信息,解析ticket值做校验。在返回的里面也非常简单,只要获取到了success就认为是允许登录。五、用一坨坨代码实现此场景大多数实现的方式都会采用继承类 ...

June 10, 2020 · 2 min · jiezi

图解23种设计模式TypeScript版前端切图仔提升内功的必经之路

关注公众号“执鸢者”,回复“书籍”获取大量前端学习资料,回复“前端视频”获取大量前端教学视频,回复“设计模式”获取本节整体思维导图。 使用思维导图来阐述23种设计模式,并以TypeScript实现其代码,让我们前端切图崽写出的代码具有可扩展性、可复用性、减少代码冗余问题,提升自身内功。 一、设计原则 二、创建型模式创建型模式包含单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式、建造者模式。创建型模式就是创建对象的模式,抽象了实例化的过程。它帮助一个系统独立于如何创建、组合和表示它的那些对象。 关注的是对象的创建,创建型模式将创建对象的过程进行了抽象,也可以理解为将创建对象的过程进行了封装,作为客户程序仅仅需要去使用对象,而不再关心创建对象过程中的逻辑。2.1 单例模式 // 饿汉式class Singleton1 { // 1. 构造器私有化,外部不能new private constructor(){} // 2. 本类内部创建对象实例化 private static instance : Singleton1 = new Singleton1(); // 3. 提供一个公有的静态方法,返回实例对象 public static getInstance() : Singleton1 { return this.instance; }}console.log(Singleton1.getInstance(), '11111');// 懒汉式class Singleton2 { private constructor(){} private static instance: Singleton2 = null; public static getInstance() : Singleton2 { if (this.instance === null) { this.instance = new Singleton2(); } return this.instance; }}console.log(Singleton2.getInstance(), '2222')2.2 简单工厂模式 ...

June 10, 2020 · 17 min · jiezi

设计模式之美二-面向对象3

7. 接口 vs 抽象类的区别,使用普通类模拟抽象类和接口7.1 抽象类定义: abstract关键词修饰抽象类特征:抽象类不能被实例化,只能被继承(extends)抽象类可以包含属性和方法,方法既可以是包含代码实现的方法,也可以是不含代码实现的方法。不包含代码实现的方法叫做抽象方法子类继承抽象类,必须实现抽象类中的所有抽象方法Demo 记录日志抽象类// 抽象类public abstract class Logger { private String name; private boolean enabled; private Level minPermittedLevel; //构造函数 1-函数名与类名相同 2-不用定义返回值(不用加void)3-不用写return public Logger(String name, boolean enabled, Level minPermittedLevel) { this.name = name; this.enabled = enabled; this.minPermittedLevel = minPermittedLevel; } public void log(Level level, String message) { boolean loggable = enabled && (minPermittedLevel.intValue() <= level.intValue()); if (!loggable) return; doLog(level, message); } //抽象方法 protected abstract void doLog(Level level, String message);}// 抽象类的子类:输出日志到文件public class FileLogger extends Logger { private Writer fileWriter; public FileLogger(String name, boolean enabled, Level minPermittedLevel, String filepath) { super(name, enabled, minPermittedLevel); this.fileWriter = new FileWriter(filepath); } @Override public void doLog(Level level, String mesage) { // 格式化level和message,输出到日志文件 fileWriter.write(...); }}// 抽象类的子类: 输出日志到消息中间件(比如kafka)public class MessageQueueLogger extends Logger { private MessageQueueClient msgQueueClient; public MessageQueueLogger(String name, boolean enabled, Level minPermittedLevel, MessageQueueClient msgQueueClient) { super(name, enabled, minPermittedLevel); this.msgQueueClient = msgQueueClient; } @Override protected void doLog(Level level, String mesage) { // 格式化level和message,输出到消息中间件 msgQueueClient.send(...); }}7.2 接口定义:interface 关键字特征:接口不能被实例化,只能被实现(implements)接口不能包含属性(也就是成员变量)和普通方法接口只能声明抽象方法,即方法不能包含代码实现类实现接口的时候,必须实现接口声明的所有方法Demo// 接口public interface Filter { void doFilter(RpcRequest req) throws RpcException;}// 接口实现类:鉴权过滤器public class AuthencationFilter implements Filter { @Override public void doFilter(RpcRequest req) throws RpcException { //...鉴权逻辑.. }}// 接口实现类:限流过滤器public class RateLimitFilter implements Filter { @Override public void doFilter(RpcRequest req) throws RpcException { //...限流逻辑... }}// 过滤器使用demopublic class Application { // filters.add(new AuthencationFilter()); // filters.add(new RateLimitFilter()); private List<Filter> filters = new ArrayList<>(); public void handleRpcRequest(RpcRequest req) { try { for (Filter filter : fitlers) { filter.doFilter(req); } } catch(RpcException e) { // ...处理过滤结果... } // ...省略其他处理逻辑... }}7.3 基于接口而非实现编程,基于抽象而非实现编程(两句话一个意思)接口:本质上接口是一组“协议”或“约定”,是功能提供者 提供给 使用者 的一个“功能列表”在具体的代码层面理解这句话,接口可以理解为编程语言中的接口或者抽象类注意问题:函数的命名不能暴露任何实现细节。比如,前面提到的 uploadToAliyun() 就不符合要求,应该改为去掉 aliyun 这样的字眼,改为更加抽象的命名方式,比如:upload()封装具体的实现细节。比如,跟阿里云相关的特殊上传(或下载)流程不应该暴露给调用者。我们对上传(或下载)流程进行封装,对外提供一个包裹所有上传(或下载)细节的方法,给调用者使用。7.4 多用组合少用继承为什么不推荐使用继承?继承是面向对象的四大特性之一,用来表示类之间的 is-a 关系,可以解决代码复用的问题。虽然继承有诸多作用,但继承层次过深、过复杂,也会影响到代码的可维护性。在这种情况下,我们应该尽量少用,甚至不用继承。组合相比继承有哪些优势?继承主要有三个作用:表示 is-a 关系,支持多态特性,代码复用。而这三个作用都可以通过组合、接口、委托三个技术手段来达成。除此之外,利用组合还能解决层次过深、过复杂的继承关系影响代码可维护性的问题。如何判断该用组合还是继承?尽管我们鼓励多用组合少用继承,但组合也并不是完美的,继承也并非一无是处。在实际的项目开发中,我们还是要根据具体的情况,来选择该用继承还是组合。如果类之间的继承结构稳定,层次比较浅,关系不复杂,我们就可以大胆地使用继承。反之,我们就尽量使用组合来替代继承。除此之外,还有一些设计模式、特殊的应用场景,会固定使用继承或者组合。

June 6, 2020 · 2 min · jiezi

设计模式抽象工厂模式

上篇文章,我们介绍了简单工厂模式和工厂方法模式,今天我们要介绍一下抽象工厂模式。我们还用上面的例子。 接上文说,工厂采用了新的设计模式之后,生产力爆棚,可是,好景不长,突然有一天,新需求来了:目前的电影和音乐不太符合大众的精细化喜好了,我们想要生产流行音乐、小众音乐、流行电影、小众电影(关键词:流行、小众、电影、音乐)。 工厂经过一番深思熟虑之后,好办! interface ArtFactory{ //创建音乐方法 public function createMusic(); //创建电影方法 public function createMovie();}我们首先创建一个艺术工厂的接口,里面放生产电影和音乐的两条生产线。接下来我们来创建2个子工厂(要实现艺术工厂接口的方法),分别来生产流行音乐和电影、小众音乐和电影。 //流行工厂class PopArtFactory implements ArtFactory{ /** * 流行电影 * * @return PopMoive */ public function createMovie() { // TODO: Implement createMovie() method. return new PopMoive(); } /** * 流行音乐 * * @return PopMusic */ public function createMusic() { // TODO: Implement createMusic() method. return new PopMusic(); }}//小众工厂class NotPopArtFactory implements ArtFactory{ /** * 制造音乐 * * @return NotPopMusic */ public function createMusic() { // TODO: Implement createMusic() method. return new NotPopMusic(); } /** * 制造电影`` * * @return NotPopMovie */ public function createMovie() { // TODO: Implement createMovie() method. return new NotPopMovie(); }}同时我们还定义了两种产品(接口):电影和音乐 ...

June 6, 2020 · 1 min · jiezi

设计模式之美二-面向对象1

设计原则与思想:面向对象(11讲)1. 什么是面向对象编程(OOP)面向对象编程是一种编程范式或编程风格。它以类或对象作为组织代码的基本单元,并将封装、抽象、继承、多态四个特性,作为代码设计和实现的基石2. 什么是面向对象编程语言面向对象编程语言是支持类或对象的语法机制,并有现成的语法机制,能方便地实现面向对象编程四大特性(封装、抽象、继承、多态)的编程语言3. 面向对象编程和面向对象编程语言之间的关系面向对象编程一般使用面向对象编程语言来进行,但是,不用面向对象编程语言,我们照样可以进行面向对象编程。反过来讲,即便我们使用面向对象编程语言,写出来的代码也不一定是面向对象编程风格的,也有可能是面向过程编程风格的4. UML 统一建模语言学习成本较高,可以适当简单学习5. 封装、继承、多态、抽象分别解决哪些编程问题* 封装概念:封装也叫作信息隐藏或者数据访问保护,类通过暴露有限的访问接口,授权外部仅能通过类提供的方法(函数)来访问内部的信息和数据作用:保护数据不被随意修改,提高代码的可维护性仅暴露有限的必要接口,提高类的易用性封装特性,必须使用访问控制权限Demo: 金融系统简化版虚拟钱包public class Wallet { private String id;//钱包唯一编号 private long createTime;//钱包创建时间 private BigDecimal balance;//钱包余额 //BigDecimal 对数字进行精度计算,返回的是对象,不能通过传统+ - * / 计算,而是必须调用相应的方法 private long balanceLastModifiedTime;//上次钱包余额变更时间 //构造函数,完成对象初始化。Java构造函数的名称必须与类名相同,包括大小写;构造函数没有返回值,也不能用void修饰; public Wallet() { this.id = IdGenerator.getInstance().generate();//全局唯一ID生成器 this.createTime = System.currentTimeMillis(); this.balance = BigDecimal.ZERO;//0 用于和0比较大小 this.balanceLastModifiedTime = System.currentTimeMillis();//获取时间,毫秒级 } public String getId() { return this.id; } public long getCreateTime() { return this.createTime; } public BigDecimal getBalance() { return this.balance; } public long getBalanceLastModifiedTime() { return this.balanceLastModifiedTime; } public void increaseBalance(BigDecimal increasedAmount) { if (increasedAmount.compareTo(BigDecimal.ZERO) < 0) { throw new InvalidAmountException("..."); } this.balance.add(increasedAmount);//添加数值 this.balanceLastModifiedTime = System.currentTimeMillis(); } public void decreaseBalance(BigDecimal decreasedAmount) { if (decreasedAmount.compareTo(BigDecimal.ZERO) < 0) { throw new InvalidAmountException("..."); } if (decreasedAmount.compareTo(this.balance) > 0) { throw new InsufficientAmountException("..."); } this.balance.subtract(decreasedAmount);//减去数值 this.balanceLastModifiedTime = System.currentTimeMillis(); }}解析从业务的角度来说,id、createTime 在创建钱包的时候就确定好了,之后不应该再被改动,所以,我们并没有在 Wallet 类中,暴露 id、createTime 这两个属性的任何修改方法,比如 set 方法。所以,在 Wallet 类的构造函数内部将其初始化设置好,而不是通过构造函数的参数来外部赋值。对于钱包余额 balance 这个属性,从业务的角度来说,只能增或者减,不会被重新设置。所以,我们在 Wallet 类中,只暴露了 increaseBalance() 和 decreaseBalance() 方法,并没有暴露 set 方法。对于 balanceLastModifiedTime 这个属性,它完全是跟 balance 这个属性的修改操作绑定在一起的。只有在 balance 修改的时候,这个属性才会被修改。所以,我们把 balanceLastModifiedTime 这个属性的修改操作完全封装在了increaseBalance() 和 decreaseBalance() 两个方法中,不对外暴露任何修改这个属性的方法和业务细节。这样也可以保证 balance 和 balanceLastModifiedTime 两个数据的一致性。抽象概念: 抽象是如何隐藏方法的具体实现,让使用者只需要关心调用哪些方法,不需要知道具体如何实现抽象可以通过接口类(Java中的interface关键字) 或 抽象类(Java中的abstract关键字)来实现作用:提高代码的可扩展性、维护性,修改时不需要改变定义,减少代码的改动范围抽象是处理复杂系统的有效手段,能有效过滤掉不必要关注的信息Demo: 图片存储功能public interface IPictureStorage { // void 是空,在方法声明中表示该方法没有返回值 void savePicture(Picture picture); Image getPicture(String pictureId); void deletePicture(String pictureId); void modifyMetaInfo(String pictureId, PictureMetaInfo metaInfo);}public class PictureStorage implements IPictureStorage { // ...省略其他属性... @Override public void savePicture(Picture picture) { ... } @Override public Image getPicture(String pictureId) { ... } @Override public void deletePicture(String pictureId) { ... } @Override public void modifyMetaInfo(String pictureId, PictureMetaInfo metaInfo) { ... }}解析在上面的这段代码中,我们利用 Java 中的 interface 接口语法来实现抽象特性调用者在使用图片存储功能的时候,只需要了解 IPictureStorage 这个接口类暴露了哪些方法就可以了,不需要去查看 PictureStorage 类里的具体实现逻辑举个简单例子,比如 getAliyunPictureUrl() 就不是一个具有抽象思维的命名,如果更换存储设备,那这个命名也要随之被修改。相反,如果我们定义一个比较抽象的函数,比如叫作 getPictureUrl(),那即便内部存储方式修改了,我们也不需要修改命名。继承概念:继承用来表示类与类之间is-a关系,可分为单继承和多继承实现继承,需要语言的语法支持,Java 使用 extends 关键字来实现继承,C++ 使用冒号(class B : public A),Python 使用 paraentheses(),Ruby 使用 <单继承:Java、PHP、C#、Ruby 等多继承:C++、Python、Perl 等作用: 提高代码复用性,比如通用的方法抽象到父类缺点: 过度使用继承,继承层次过深、过复杂,就会导致代码的可读性、可维护性变差解决思路:多用组合少用继承多态概念:父类,被多个子类继承,如果父类的某个方法,在多个子类中被重写,表现出不同功能,就是多态(同一个类的不同子类表现不同形态)实现方法:继承+方法重写 -Demo1利用接口类语法(C++不支持) -Demo2利用duck-typing语法(仅有 Python、JavaScript支持) -Demo3作用: 多态可以提高代码的扩展性和复用性Demo1//继承+方法重写public class DynamicArray { private static final int DEFAULT_CAPACITY = 10; protected int size = 0; protected int capacity = DEFAULT_CAPACITY; protected Integer[] elements = new Integer[DEFAULT_CAPACITY]; public int size() { return this.size; } public Integer get(int index) { return elements[index];} //...省略n多方法... public void add(Integer e) { ensureCapacity(); elements[size++] = e; } protected void ensureCapacity() { //...如果数组满了就扩容...代码省略... }}public class SortedDynamicArray extends DynamicArray { @Override public void add(Integer e) { ensureCapacity(); int i; for (i = size-1; i>=0; --i) { //保证数组中的数据有序 if (elements[i] > e) { elements[i+1] = elements[i]; } else { break; } } elements[i+1] = e; ++size; }}public class Example { // 静态方法,直接类名.方法调用 public static void test(DynamicArray dynamicArray) { dynamicArray.add(5); dynamicArray.add(1); dynamicArray.add(3); for (int i = 0; i < dynamicArray.size(); ++i) { System.out.println(dynamicArray.get(i)); } } //main()方法是Java应用程序入口方法,程序运行,第一个执行的方法就是main()方法 public static void main(String args[]) { DynamicArray dynamicArray = new SortedDynamicArray(); test(dynamicArray); // 打印结果:1、3、5 }}解析多态这种特性也需要编程语言提供特殊的语法机制来实现。在上面的例子中,我们用到了三个语法机制来实现多态。第一,支持父类对象引用子类对象,也就是可以将 SortedDynamicArray 传递给 DynamicArray。第二,支持继承,也就是 SortedDynamicArray 继承了 DynamicArray,才能将 SortedDyamicArray 传递给 DynamicArray第三,支持子类可以重写(override)父类中的方法,也就是 SortedDyamicArray 重写了 DynamicArray 中的 add() 方法。通过这三种语法机制配合在一起,我们就实现了在 test() 方法中,子类 SortedDyamicArray 替换父类 DynamicArray,执行子类 SortedDyamicArray 的 add() 方法,也就是实现了多态特性。Demo2//利用接口类实现public interface Iterator { String hasNext();//检测序列是否还有元素 String next();//获取序列下一个元素 String remove();//将迭代器新返回的元素删除}public class Array implements Iterator { private String[] data; public String hasNext() { ... } public String next() { ... } public String remove() { ... } //...省略其他方法...}public class LinkedList implements Iterator { private LinkedListNode head; public String hasNext() { ... } public String next() { ... } public String remove() { ... } //...省略其他方法... }public class Demo { private static void print(Iterator iterator) { while (iterator.hasNext()) { System.out.println(iterator.next()); } } public static void main(String[] args) { Iterator arrayIterator = new Array(); print(arrayIterator); Iterator linkedListIterator = new LinkedList(); print(linkedListIterator); }}解析在这段代码中,Iterator 是一个接口类,定义了一个可以遍历集合数据的迭代器。Array 和 LinkedList 都实现了接口类 Iterator我们通过传递不同类型的实现类(Array、LinkedList)到 print(Iterator iterator) 函数中,支持动态的调用不同的 next()、hasNext() 实现。Demo3class Logger: def record(self): print(“I write a log into file.”) class DB: def record(self): print(“I insert data into db. ”) def test(recorder): recorder.record()def demo(): logger = Logger() db = DB() test(logger) test(db)解析从这段代码中看出,duck-typing 实现多态的方式非常灵活。Logger 和 DB 两个类没有任何关系,既不是继承关系,也不是接口和实现的关系,但是只要它们都有定义了 record() 方法,就可以被传递到 test() 方法中在实际运行的时候,执行对应的 record() 方法。也就是说,只要两个类具有相同的方法,就可以实现多态,并不要求两个类之间有任何关系,这就是所谓的 duck-typing,是一些动态语言所特有的语法机制。而像 Java 这样的静态语言,通过继承实现多态特性,必须要求两个类之间有继承关系,通过接口实现多态特性,类必须实现对应的接口。扩展:Java,PHP不支持多继承原因:多重继承有副作用:菱形继承(钻石问题) 假设类 B 和类 C 继承自类 A,且都重写了类 A 中的同一个方法,而类 D 同时继承了类 B 和类 C,那么此时类 D 会继承 B、C 的方法,那对于 B、C 重写的 A 中的方法,类 D 会继承哪一个呢?这里就会产生歧义。Python多继承的实现方法:针对多继承时,多个父类的同名方法,Python采用MRO,在多继承时,判断方法、属性的调用路径 在当前类中找到方法,就直接执行,不再搜索;如果没有找到,就查找下一个类是否有对应方法,如果找到就直接执行,不再搜索;直到最后一个类,没找到就报错

June 5, 2020 · 3 min · jiezi

设计模式之美一-导学篇

导学篇为什么要学设计模式1. 程序员的看家本领!数据结构与算法教你写出高效的代码,设计模式教你写出高质量的代码写代码可以说是程序员天天要干的事情,要是代码都写不好,最基本的看家本领都练不好,成天堆砌烂代码,写代码还有啥意思呢?那还干啥程序员啊!写出“能用”代码的人比比皆是,但是,并不是每个人都能写出“好用”的代码。只会写能用的代码,我们永远成长不成大牛,成长不成最优秀的那批人。很多工程师写了多年代码,代码功力一点都没长进,编写的代码仍然只是能用即可,能运行就好。平日的工作就是修修补补、抄抄改改,一直在做重复劳动,能力也一直停留在“会干活”的层面,就像高速路上的收银员,只能算是一个“熟练工”。“为什么要有这种设计原则、思想或者模式?它能解决什么编程问题?有哪些应用场景?又该如何权衡、恰当地在项目中应用?”等等。思考,回顾,思考,实践很多程序员都已经意识到基础知识的重要性,觉得要夯实基础,才能走得更远,但同时对于如何将基础知识转化成开发“生产力”仍然有些疑惑。所以,你可能看了很多基础的书籍,比如操作系统、组成原理、编译原理等,但还是觉得很迷茫,觉得在开发中用不上,起码在平时的 CRUD 业务开发中用不上。实际上,这些基础的知识确实很难直接转化成开发“生产力”。但是,它能潜移默化地、间接地提高你对技术的理解。设计模式、数据结构、算法更像是一道儿的,相比那些更加基础的学科,设计模式能更直接地提高你的开发能力2. 为什么学习设计模式1.应对面试中的设计模式相关问题 BAT-TMD区分度选项2.告别写被人吐槽的烂代码 Talk is cheap,show me the code代码能力是一个程序员最基础的能力,是基本功,是展示一个程序员基础素养的最直接的衡量标准你写的代码,实际上就是你名片烂代码,比如命名不规范、类设计不合理、分层不清晰、没有模块化概念、代码结构混乱、高度耦合等等3.提高复杂代码的设计和开发能力 如何分层、分模块?应该怎么划分类?每个类应该具有哪些属性、方法?怎么设计类之间的交互?该用继承还是组合?该使用接口还是抽象类?怎样做到解耦、高内聚低耦合?该用单例模式还是静态方法?用工厂模式创建对象还是直接 new 出来?如何避免引入设计模式提高扩展性的同时带来的降低可读性问题?4.让读源码、学框架事半功倍 优秀的开源项目、框架、中间件,代码量、类的个数都会比较多,类结构、类之间的关系极其复杂,常常调用来调用去。所以,为了保证代码的扩展性、灵活性、可维护性等,代码中会使用到很多设计模式、设计原则或者设计思想。如果你不懂这些设计模式、原则、思想,在看代码的时候,你可能就会琢磨不透作者的设计思路,对于一些很明显的设计思路,你可能要花费很多时间才能参悟。相反,如果你对设计模式、原则、思想非常了解,一眼就能参透作者的设计思路、设计初衷,很快就可以把脑容量释放出来,重点思考其他问题,代码读起来就会变得轻松了。5.为你的职场发展做铺垫 3. 哪些维度评判代码质量好坏可维护性“代码易维护” 就是指,在不破坏原有代码设计、不引入新的 bug 的情况下,能够快速地修改或者添加代码代码的可读性好、简洁、可扩展性好,就会使得代码易维护更细化地讲,如果代码分层清晰、模块化好、高内聚低耦合、遵从基于接口而非实现编程的设计原则等等,那就可能意味着代码易维护可读性看代码是否符合编码规范命名是否达意注释是否详尽函数是否长短合适模块划分是否清晰是否符合高内聚低耦合等等可扩展性代码的可扩展性表示,我们在不修改或少量修改原有代码的情况下,通过扩展的方式添加新的功能代码。说直白点就是,代码预留了一些功能扩展点,你可以把新功能代码,直接插到扩展点上,而不需要因为要添加一个功能而大动干戈,改动大量的原始代码。对修改关闭,对扩展开放灵活性如果一段代码易扩展、易复用或者易用,我们都可以称这段代码写得比较灵活简洁性KISS原则(keep it simple stupid)代码简单、逻辑清晰,也就意味着易读、易维护思从深而行之简,用最简单的方法解决最复杂的问题可复用性尽量减少重复代码的编写,复用已有的代码面向对象特性,继承、多态存在的目的之一,就是为了提高代码的可复用性设计原则中的单一职责原则也跟代码的可复用性相关重构技巧,解耦、高内聚、模块化等都能提高代码的可复用性可测试性容易编写单元测试4. 如何写出高质量代码要写出满足多种评价标准的高质量代码,我们需要掌握一些更加细化、更加能落地的编程方法论,包括面向对象设计思想、设计原则、设计模式、编码规范、重构技巧等面向对象中的继承、多态能让我们写出可复用的代码编码规范能让我们写出可读性好的代码设计原则中的单一职责、DRY、基于接口而非实现、里式替换原则等,可以让我们写出可复用、灵活、可读性好、易扩展、易维护的代码设计模式可以让我们写出易扩展的代码持续重构可以时刻保持代码的可维护性5. 教学大纲(面向对象、设计原则、设计模式、编程规范、重构之间的关系) 面向对象主流的编程范式或编程风格有三类,面向过程、面向对象、函数式编程7大知识点① 面向对象的四大特性:封装、抽象、继承、多态② 面向对象和面向过程编程的区别和联系③ 面向对象分析,面向对象设计,面向对象编程④ 接口和抽象类的区别以及各自应用场景⑤ 基于接口而非实现编程的设计思想⑥ 多用组合少用继承的设计思想⑦ 面向过程的贫血模式 和 面向对象的充血模式设计原则理解各类设计原则定义、掌握设计初衷、能解决哪些编程问题、有哪些应用场景SOLID原则-SRP 单一职权原则SOLID原则-OCP 开闭原则SOLID原则-LSP 里式替换原则SOLID原则-ISP 接口隔离原则SOLID原则-DIP 依赖倒置原则DRY 原则KISS 原则YAGNI原则LOD 法则设计模式针对软件开发中经常遇到的一些设计问题,总结出的一套解决方案或设计思路,大部分的设计模式要解决的都是代码可拓展性问题23种经典设计模式,分为以下几类(1)创建型 4种常用:①单例模式②工厂模式③建造者模式 不常用:④原型模式(2)结构型 7种常用:⑤代理模式⑥桥接模式⑦装饰者模式⑧适配器模式 不常用:⑨门面模式⑩组合模式⑪享元模式(3)行为型 11种常用:⑫观察者模式⑬模板模式⑭策略模式⑮职责链模式⑯迭代器模式⑰状态模式 不常用:⑱访问者模式⑲备忘录模式⑳命令模式㉑解释器模式㉒中介模式㉓对象模式 编程规范代码规范主要解决代码的可读性问题,比如如何给变量、类、函数命名、如何写代码注释等问题《重构代码大全》《代码整洁之道》此处总结20条规范代码重构重构的目的(why)、对象(what)、时机(when)、方法(how)保证重构不出错的技术手段:单元测试和代码的可测试性两种不同规范的重构:大重构(大规模高层次)、小重构(小规模低层次)五者之间联系面向对象编程,因为具有丰富的特性(封装、抽象、继承、多态),可以实现很多复杂的设计思路,是很多设计原则、设计模式等编码实现的基础。设计原则是指导我们代码设计的一些经验总结,对于某些场景下,是否应该应用某种设计模式,具有指导意义。比如,“开闭原则”是很多设计模式(策略、模板等)的指导原则设计模式是针对软件开发中经常遇到的一些设计问题,总结出来的一套解决方案或者设计思路。应用设计模式的主要目的是提高代码的可扩展性。从抽象程度上来讲,设计原则比设计模式更抽象。设计模式更加具体、更加可执行编程规范主要解决的是代码的可读性问题。编码规范相对于设计原则、设计模式,更加具体、更加偏重代码细节、更加能落地。持续的小重构依赖的理论基础主要就是编程规范重构作为保持代码质量不下降的有效手段,利用的就是面向对象、设计原则、设计模式、编码规范这些理论

June 5, 2020 · 1 min · jiezi

设计模式

什么是设计模式 每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必重复劳动底层思维:向下,如何把握机器底层从微观理解对象构造抽象思维:向上,如何将我们的周围世界抽象为程序代码 面向对象组件封装设计模式架构模式向下:深入理解三大面向对象机制封装,隐藏内部实现继承,复用现有代码多态,改写对象行为 向上:深刻把握

June 5, 2020 · 1 min · jiezi

重学-Java-设计模式实战桥接模式多支付渠道微信支付宝与多支付模式刷脸指纹场景

作者:小傅哥博客:https://bugstack.cn - 编写系列原创专题文章 沉淀、分享、成长,让自己和他人都能有所收获!?一、前言为什么你的代码那么多ifelse 同类的业务、同样的功能,怎么就你能写出来那么多ifelse。很多时候一些刚刚从校园进入企业的萌新,或者一部分从小公司跳槽到大企业的程序员,初次承接业务需求的时候,往往编码还不成熟,经常一杆到底的写需求。初次实现确实很快,但是后期维护和扩展就十分痛苦。因为一段代码的可读性阅读他后期的维护成本也就越高。 设计模式是可以帮助你改善代码 很多时候你写出来的ifelse都是没有考虑使用设计模式优化,就像;同类服务的不同接口适配包装、同类物料不同组合的建造、多种奖品组合的营销工厂等等。它们都可以让你代码中原本使用if判断的地方,变成一组组类和面向对象的实现过程。 怎么把设计模式和实际开发结合起来 多从实际场景思考,只找到代码优化的最佳点,不要可以想着设计模式的使用。就像你最开始看设计模式适合,因为没有真实的场景模拟案例,都是一些画圆形、方形,对新人或者理解能力还不到的伙伴来说很不友好。所以即使学了半天 ,但实际使用还是摸不着头脑。 二、开发环境JDK 1.8Idea + Maven涉及工程三个,可以通过关注公众号:bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)工程描述itstack-demo-design-7-01使用一坨代码实现业务需求itstack-demo-design-7-02通过设计模式优化改造代码,产生对比性从而学习三、桥接模式介绍 桥接模式的主要作用就是通过将抽象部分与实现部分分离,把多种可匹配的使用进行组合。说白了核心实现也就是在A类中含有B类接口,通过构造函数传递B类的实现,这个B类就是设计的桥。 那么这样的桥接模式,在我们平常的开发中有哪些场景 JDBC多种驱动程序的实现、同品牌类型的台式机和笔记本平板、业务实现中的多类接口同组过滤服务等。这些场景都比较适合使用桥接模式进行实现,因为在一些组合中如果有如果每一个类都实现不同的服务可能会出现笛卡尔积,而使用桥接模式就可以非常简单。 四、案例场景模拟 随着市场的竞争在支付服务行业出现了微信和支付宝还包括一些其他支付服务,但是对于商家来说并不希望改变用户习惯。就像如果我的地摊只能使用微信或者只能使用支付宝付款,那么就会让我顾客伤心,鸡蛋灌饼也卖不动了。 在这个时候就出现了第三方平台,把市面上综合占据市场90%以上的支付服务都集中到自己平台中,再把这样的平台提供给店铺、超市、地摊使用,同时支持人脸、扫描、密码多种方式。 我们这个案例就模拟一个这样的第三方平台来承接各个支付能力,同时使用自家的人脸让用户支付起来更加容易。那么这里就出现了多支付与多模式的融合使用,如果给每一个支付都实现一次不同的模式,即使是继承类也需要开发好多。而且随着后面接入了更多的支付服务或者支付方式,就会呈爆炸似的扩展。 所以你现在可以思考一下这样的场景该如何实现? 五、用一坨坨代码实现产品经理说老板要的需求,要尽快上,kpi你看着弄! 既然你逼我那就别怪我无情,还没有我一个类写不完的需求!反正写完就完事了,拿完绩效也要走了天天逼着写需求,代码越来越乱心疼后面的兄弟3秒。 1. 工程结构itstack-demo-design-7-01└── src └── main └── java └── org.itstack.demo.design └── PayController.java只有一个类里面都是ifelse,这个类实现了支付和模式的全部功能。2. 代码实现public class PayController { private Logger logger = LoggerFactory.getLogger(PayController.class); public boolean doPay(String uId, String tradeId, BigDecimal amount, int channelType, int modeType) { // 微信支付 if (1 == channelType) { logger.info("模拟微信渠道支付划账开始。uId:{} tradeId:{} amount:{}", uId, tradeId, amount); if (1 == modeType) { logger.info("密码支付,风控校验环境安全"); } else if (2 == modeType) { logger.info("人脸支付,风控校验脸部识别"); } else if (3 == modeType) { logger.info("指纹支付,风控校验指纹信息"); } } // 支付宝支付 else if (2 == channelType) { logger.info("模拟支付宝渠道支付划账开始。uId:{} tradeId:{} amount:{}", uId, tradeId, amount); if (1 == modeType) { logger.info("密码支付,风控校验环境安全"); } else if (2 == modeType) { logger.info("人脸支付,风控校验脸部识别"); } else if (3 == modeType) { logger.info("指纹支付,风控校验指纹信息"); } } return true; }}上面的类提供了一个支付服务功能,通过提供的必要字段;用户ID、交易ID、金额、渠道、模式,来控制支付方式。以上的ifelse应该是最差的一种写法,即使写ifelse也是可以优化的方式去写的。3. 测试验证3.1 编写测试类@Testpublic void test_pay() { PayController pay = new PayController(); System.out.println("\r\n模拟测试场景;微信支付、人脸方式。"); pay.doPay("weixin_1092033111", "100000109893", new BigDecimal(100), 1, 2); System.out.println("\r\n模拟测试场景;支付宝支付、指纹方式。"); pay.doPay("jlu19dlxo111","100000109894",new BigDecimal(100), 2, 3);}以上分别测试了两种不同的支付类型和支付模式;微信人脸支付、支付宝指纹支付3.2 测试结果模拟测试场景;微信支付、人脸方式。23:05:59.152 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟微信渠道支付划账开始。uId:weixin_1092033111 tradeId:100000109893 amount:10023:05:59.155 [main] INFO o.i.demo.design.pay.mode.PayCypher - 人脸支付,风控校验脸部识别23:05:59.155 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟微信渠道支付风控校验。uId:weixin_1092033111 tradeId:100000109893 security:true23:05:59.155 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟微信渠道支付划账成功。uId:weixin_1092033111 tradeId:100000109893 amount:100模拟测试场景;支付宝支付、指纹方式。23:05:59.156 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟支付宝渠道支付划账开始。uId:jlu19dlxo111 tradeId:100000109894 amount:10023:05:59.156 [main] INFO o.i.demo.design.pay.mode.PayCypher - 指纹支付,风控校验指纹信息23:05:59.156 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟支付宝渠道支付风控校验。uId:jlu19dlxo111 tradeId:100000109894 security:true23:05:59.156 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟支付宝渠道支付划账成功。uId:jlu19dlxo111 tradeId:100000109894 amount:100Process finished with exit code 0从测试结果看已经满足了我们的不同支付类型和支付模式的组合,但是这样的代码在后面的维护以及扩展都会变得非常复杂。六、桥接模式重构代码接下来使用桥接模式来进行代码优化,也算是一次很小的重构。 ...

June 5, 2020 · 3 min · jiezi

设计模式简单工厂模式和工厂方法模式

工厂模式是常用的模式之一(那是相当重要~),它属于创建类型,通过“工厂”的字面意思也可以看出来工厂负责生产产品,顾客只需要关注产品就行了,不需要关注产品的生产过程。这样做的好处就是降低顾客和产品之间的耦合度、提高了代码的复用率。 工厂模式分为:简单工厂模式、工厂方法模式、抽象工厂模式。 简单工厂模式:就是简单的只生产一种产品,你想要其他产品,那不好意思,我生产不了,只能最基本的解决顾客和工厂之间的耦合问题。 具体的代码逻辑:利用静态方法创建对象。 工厂方法模式:在简单工厂的基础上,可以生产同种类型多种产品,但是不能为该产品增加新的特性(因为不符合开闭原则)。 具体的代码逻辑:去掉简单工厂模式中创建对象的静态方法,定义创建工厂的接口(基类),具体的工厂可以实现(或继承)该工厂接口(或基类),同时定义产品的接口(或基类),具体的产品可以实现(或继承)该产品接口(基类),工厂实际生产什么产品交给具体的工厂类和具体的产品类。这样我们增加新的同种类产品工厂,但是不能为产品增加新的特性(因为不符合开闭原则)。 抽象工厂模式:不同的工厂可以生产相同属性的不同的产品,但是不能生产没有报备的新产品(因为不符合开闭原则)。 具体代码逻辑:提供了创建工厂的接口,该接口里面需要声明工厂可以生产哪些产品,同时提供了创建这些产品的接口,该接口里面需要声明该产品的属性,这样可以实现具体的工厂可以在现有产品的基础上进行升级和改造,但是不能生产没有声明的新产品(因为不符合开闭原则)。 举例: 我要艺术作品生产商,我想把我手里的电影作品(包含艺术家和作品名称)给生产出来。嗯,需求简单,那就用简单工厂模式,老规矩上代码: class MovieFactory{ /** * 生产电影 * * @return MovieProduction */ public function generateMovie() { return new MovieProduction(); }}我们创建一个电影工厂来生产电影作品。 class MovieProduction{ // 艺术家 protected $_artist = null; // 作品名 protected $_production = null; /** * 设置艺术家 * * @param double $num 数字 * @return void */ public function setArtist($name) { $this->_artist = $name; } /** * 获取艺术家 * * @return null */ public function getArtist() { return $this->_artist; } /** * 设置作品 * * @param null $production */ public function setProduction($production) { $this->_production = $production; } /** * 获取作品 * * @return null */ public function getProduction() { return $this->_production; } /** * 获取作品 * * @return string 字符串 */ public function getMovie() { return '来自' . $this->_artist . '的电影作品:《' . $this->_production . '》'; }}电影作品包含艺术家(artist)和作品(production)两个信息。还提供一个直接获取产品的方法getMovie. ...

June 4, 2020 · 2 min · jiezi

重学-Java-设计模式实战适配器模式

作者:小傅哥博客:https://bugstack.cn 沉淀、分享、成长,让自己和他人都能有所收获!?一、前言擦屁屁纸80%的面积都是保护手的! 工作到3年左右很大一部分程序员都想提升自己的技术栈,开始尝试去阅读一些源码,例如Spring、Mybaits、Dubbo等,但读着读着发现越来越难懂,一会从这过来一会跑到那去。甚至怀疑自己技术太差,慢慢也就不愿意再触碰这部分知识。 而这主要的原因是一个框架随着时间的发展,它的复杂程度是越来越高的,从最开始只有一个非常核心的点到最后开枝散叶。这就像你自己开发的业务代码或者某个组件一样,最开始的那部分核心代码也许只能占到20%,而其他大部分代码都是为了保证核心流程能正常运行的。所以这也是你读源码费劲的一部分原因。 框架中用到了设计模式吗? 框架中不仅用到设计模式还用了很多,而且有些时候根本不是一个模式的单独使用,而是多种设计模式的综合运用。与大部分小伙伴平时开发的CRUD可就不一样了,如果都是if语句从上到下,也就算得不上什么框架了。就像你到Spring的源码中搜关键字Adapter,就会出现很多实现类,例如;UserCredentialsDataSourceAdapter。而这种设计模式就是我们本文要介绍的适配器模式。 适配器在生活里随处可见 如果提到在日常生活中就很多适配器的存在你会想到什么?在没有看后文之前可以先思考下。 二、开发环境JDK 1.8Idea + Maven涉及工程三个,可以通过关注公众号:bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)工程描述itstack-demo-design-6-00场景模拟工程;模拟多个MQ消息体itstack-demo-design-6-01使用一坨代码实现业务需求itstack-demo-design-6-02通过设计模式优化改造代码,产生对比性从而学习三、适配器模式介绍 适配器模式的主要作用就是把原本不兼容的接口,通过适配修改做到统一。使得用户方便使用,就像我们提到的万能充、数据线、MAC笔记本的转换头、出国旅游买个插座等等,他们都是为了适配各种不同的口,做的兼容。。 除了我们生活中出现的各种适配的场景,那么在业务开发中呢? 在业务开发中我们会经常的需要做不同接口的兼容,尤其是中台服务,中台需要把各个业务线的各种类型服务做统一包装,再对外提供接口进行使用。而这在我们平常的开发中也是非常常见的。 四、案例场景模拟 随着公司的业务的不断发展,当基础的系统逐步成型以后。业务运营就需要开始做用户的拉新和促活,从而保障DUA的增速以及最终ROI转换。 而这时候就会需要做一些营销系统,大部分常见的都是裂变、拉客,例如;你邀请一个用户开户、或者邀请一个用户下单,那么平台就会给你返利,多邀多得。同时随着拉新的量越来越多开始设置每月下单都会给首单奖励,等等,各种营销场景。 那么这个时候做这样一个系统就会接收各种各样的MQ消息或者接口,如果一个个的去开发,就会耗费很大的成本,同时对于后期的拓展也有一定的难度。此时就会希望有一个系统可以配置一下就把外部的MQ接入进行,这些MQ就像上面提到的可能是一些注册开户消息、商品下单消息等等。 而适配器的思想方式也恰恰可以运用到这里,并且我想强调一下,适配器不只是可以适配接口往往还可以适配一些属性信息。 1. 场景模拟工程itstack-demo-design-6-00└── src └── main └── java └── org.itstack.demo.design ├── mq │ ├── create_account.java │ ├── OrderMq.java │ └── POPOrderDelivered.java └── service ├── OrderServicejava └── POPOrderService.java这里模拟了三个不同类型的MQ消息,而在消息体中都有一些必要的字段,比如;用户ID、时间、业务ID,但是每个MQ的字段属性并不一样。就像用户ID在不同的MQ里也有不同的字段:uId、userId等。同时还提供了两个不同类型的接口,一个用于查询内部订单订单下单数量,一个用于查询第三方是否首单。后面会把这些不同类型的MQ和接口做适配兼容。2. 场景简述1.1 注册开户MQpublic class create_account { private String number; // 开户编号 private String address; // 开户地 private Date accountDate; // 开户时间 private String desc; // 开户描述 // ... get/set }1.2 内部订单MQpublic class OrderMq { private String uid; // 用户ID private String sku; // 商品 private String orderId; // 订单ID private Date createOrderTime; // 下单时间 // ... get/set }1.3 第三方订单MQpublic class POPOrderDelivered { private String uId; // 用户ID private String orderId; // 订单号 private Date orderTime; // 下单时间 private Date sku; // 商品 private Date skuName; // 商品名称 private BigDecimal decimal; // 金额 // ... get/set }1.4 查询用户内部下单数量接口public class OrderService { private Logger logger = LoggerFactory.getLogger(POPOrderService.class); public long queryUserOrderCount(String userId){ logger.info("自营商家,查询用户的订单是否为首单:{}", userId); return 10L; }}1.5 查询用户第三方下单首单接口public class POPOrderService { private Logger logger = LoggerFactory.getLogger(POPOrderService.class); public boolean isFirstOrder(String uId) { logger.info("POP商家,查询用户的订单是否为首单:{}", uId); return true; }}以上这几项就是不同的MQ以及不同的接口的一个体现,后面我们将使用这样的MQ消息和接口,给它们做相应的适配。五、用一坨坨代码实现其实大部分时候接MQ消息都是创建一个类用于消费,通过转换他的MQ消息属性给自己的方法。 ...

June 3, 2020 · 3 min · jiezi

JAVA设计模式理解与总结下代理模式适配器模式观察者模式

码了好几年代码的打字机器我,对于设计模式这个词,肯定是一点也不陌生,但是对于设计模式的理解,因为日常开发中,增删改查较多,使用设计模式思想来优化代码的机会就很少。也不乏在翻阅源码的时候,叹服于别人优秀高效的设计。所有今天抽出点时间,对设计模式做个归纳、记录,以便日后读到优秀的源码,可以自信的说,这**不就是那啥吗,我也会写~~~设计模式设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案 代理模式一个类代表另一个类的功能,在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。 代理模式在我们的生活中也很常见,例如程序员的女友想买一个法国产的某包包,她不需要亲自去法国某个卖驴的专卖店去买,而是可以在代购手中购买,并获得一些小礼物,折扣优惠等等。 静态代理在代码中,代理就是在使用者和服务提供者中间的服务,提供一些在提供的服务前后处理一些事物的功能。 卖东西人的认证(共同实现的接口) public interface Seller { void sell();}法国某经销商: public class LvFactory implements Seller{ @Override public void sell() { System.out.println("LV厂家卖包包"); }}你女朋友朋友圈某个不知名好友: class Purchase implements Seller{ private Seller seller; public Purchase(Seller factory) { this.seller = factory; } @Override public void sell() { System.out.println("坐飞机去法国"); seller.sell(); System.out.println("坐飞机回国"); }}你女朋友: public static void main(String[] args) { Seller lv = new LvFactory(); new Purchase(lv).sell();}你: 信用卡 boom~~~~~~~~~~~~~~~~~坐飞机去法国LV厂家卖包包 坐飞机回国 动态代理动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy,通过固定的规则生成。 举个?,女朋友朋友圈这个代购,代购包,也代购手表,那我找他一起买一块手表呢? ...

June 1, 2020 · 3 min · jiezi

重学-Java-设计模式实战单例模式

作者:小傅哥博客:https://bugstack.cn 沉淀、分享、成长,让自己和他人都能有所收获!?一、前言5个创建型模式的最后一个 在设计模式中按照不同的处理方式共包含三大类;创建型模式、结构型模式和行为模式,其中创建型模式目前已经介绍了其中的四个;工厂方法模式、抽象工厂模式、生成器模式和原型模式,除此之外还有最后一个单例模式。 掌握了的知识才是自己的 在本次编写的重学 Java 设计模式的编写中尽可能多的用各种场景案例还介绍设计的使用,包括我们已经使用过的场景;各种类型奖品发放、多套Redis缓存集群升级、装修公司报价清单和百份考卷题目与答案乱序,通过这些场景案例的实践感受设计模式的思想。但这些场景都是作者通过经验分离出来的,还并不是读者的知识,所以你如果希望可以融会贯通的掌握那么一定要亲力亲为的操作,事必躬亲的完成。 书不是看的是用的 在这里还是想强调一下学习方法,总有很多小伙伴对学习知识有疑惑,明明看了、看的时候也懂了,但到了实际使用的时候却用不上。或者有时候在想是不要是有更加生动的漫画或者什么对比会好些,当然这些方式可能会加快一个新人对知识的理解速度。但只要你把学习视频当电影看、学习书籍当故事看,就很难掌握这项技术栈。只有你把它用起来,逐字逐句的深挖,一点点的探求,把各项遇到的盲点全部扫清,才能让你真的掌握这项技能。 二、开发环境JDK 1.8Idea + Maven涉及工程1个,可以通过关注公众号:bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)三、单例模式介绍 单例模式可以说是整个设计中最简单的模式之一,而且这种方式即使在没有看设计模式相关资料也会常用在编码开发中。 因为在编程开发中经常会遇到这样一种场景,那就是需要保证一个类只有一个实例哪怕多线程同时访问,并需要提供一个全局访问此实例的点。 综上以及我们平常的开发中,可以总结一条经验,单例模式主要解决的是,一个全局使用的类频繁的创建和消费,从而提升提升整体的代码的性能。 四、案例场景本章节的技术所出现的场景非常简单也是我们日常开发所能见到的,例如; 数据库的连接池不会反复创建spring中一个单例模式bean的生成和使用在我们平常的代码中需要设置全局的的一些属性保存在我们的日常开发中大致上会出现如上这些场景中使用到单例模式,虽然单例模式并不复杂但是使用面却比较广。 五、7种单例模式实现单例模式的实现方式比较多,主要在实现上是否支持懒汉模式、是否线程安全中运用各项技巧。当然也有一些场景不需要考虑懒加载也就是懒汉模式的情况,会直接使用static静态类或属性和方法的方式进行处理,供外部调用。 那么接下来我们就通过实现不同方式的实现进行讲解单例模式。 0. 静态类使用public class Singleton_00 { public static Map<String,String> cache = new ConcurrentHashMap<String, String>(); }以上这种方式在我们平常的业务开发中非常场常见,这样静态类的方式可以在第一次运行的时候直接初始化Map类,同时这里我们也不需要到延迟加载在使用。在不需要维持任何状态下,仅仅用于全局访问,这个使用使用静态类的方式更加方便。但如果需要被继承以及需要维持一些特定状态的情况下,就适合使用单例模式。1. 懒汉模式(线程不安全)public class Singleton_01 { private static Singleton_01 instance; private Singleton_01() { } public static Singleton_01 getInstance(){ if (null != instance) return instance; return new Singleton_01(); }}单例模式有一个特点就是不允许外部直接创建,也就是new Singleton_01(),因此这里在默认的构造函数上添加了私有属性 private。目前此种方式的单例确实满足了懒加载,但是如果有多个访问者同时去获取对象实例你可以想象成一堆人在抢厕所,就会造成多个同样的实例并存,从而没有达到单例的要求。2. 懒汉模式(线程安全)public class Singleton_02 { private static Singleton_02 instance; private Singleton_02() { } public static synchronized Singleton_02 getInstance(){ if (null != instance) return instance; return new Singleton_02(); }}此种模式虽然是安全的,但由于把锁加到方法上后,所有的访问都因需要锁占用导致资源的浪费。如果不是特殊情况下,不建议此种方式实现单例模式。3. 饿汉模式(线程安全)public class Singleton_03 { private static Singleton_03 instance = new Singleton_03(); private Singleton_03() { } public static Singleton_03 getInstance() { return instance; }}此种方式与我们开头的第一个实例化Map基本一致,在程序启动的时候直接运行加载,后续有外部需要使用的时候获取即可。但此种方式并不是懒加载,也就是说无论你程序中是否用到这样的类都会在程序启动之初进行创建。那么这种方式导致的问题就像你下载个游戏软件,可能你游戏地图还没有打开呢,但是程序已经将这些地图全部实例化。到你手机上最明显体验就一开游戏内存满了,手机卡了,需要换了。4. 使用类的内部类(线程安全)public class Singleton_04 { private static class SingletonHolder { private static Singleton_04 instance = new Singleton_04(); } private Singleton_04() { } public static Singleton_04 getInstance() { return SingletonHolder.instance; }}使用类的静态内部类实现的单例模式,既保证了线程安全有保证了懒加载,同时不会因为加锁的方式耗费性能。这主要是因为JVM虚拟机可以保证多线程并发访问的正确性,也就是一个类的构造方法在多线程环境下可以被正确的加载。此种方式也是非常推荐使用的一种单例模式5. 双重锁校验(线程安全)public class Singleton_05 { private static Singleton_05 instance; private Singleton_05() { } public static Singleton_05 getInstance(){ if(null != instance) return instance; synchronized (Singleton_05.class){ if (null == instance){ instance = new Singleton_05(); } } return instance; }}双重锁的方式是方法级锁的优化,减少了部分获取实例的耗时。同时这种方式也满足了懒加载。6. CAS「AtomicReference」(线程安全)public class Singleton_06 { private static final AtomicReference<Singleton_06> INSTANCE = new AtomicReference<Singleton_06>(); private static Singleton_06 instance; private Singleton_06() { } public static final Singleton_06 getInstance() { for (; ; ) { Singleton_06 instance = INSTANCE.get(); if (null != instance) return instance; INSTANCE.compareAndSet(null, new Singleton_06()); return INSTANCE.get(); } } public static void main(String[] args) { System.out.println(Singleton_06.getInstance()); // org.itstack.demo.design.Singleton_06@2b193f2d System.out.println(Singleton_06.getInstance()); // org.itstack.demo.design.Singleton_06@2b193f2d }}java并发库提供了很多原子类来支持并发访问的数据安全性;AtomicInteger、AtomicBoolean、AtomicLong、AtomicReference。AtomicReference<V> 可以封装引用一个V实例,支持并发访问如上的单例方式就是使用了这样的一个特点。使用CAS的好处就是不需要使用传统的加锁方式保证线程安全,而是依赖于CAS的忙等算法,依赖于底层硬件的实现,来保证线程安全。相对于其他锁的实现没有线程的切换和阻塞也就没有了额外的开销,并且可以支持较大的并发性。当然CAS也有一个缺点就是忙等,如果一直没有获取到将会处于死循环中。7. Effective Java作者推荐的枚举单例(线程安全)public enum Singleton_07 { INSTANCE; public void test(){ System.out.println("hi~"); }}约书亚·布洛克(英语:Joshua J. Bloch,1961年8月28日-),美国著名程序员。他为Java平台设计并实作了许多的功能,曾担任Google的首席Java架构师(Chief Java Architect)。Effective Java 作者推荐使用枚举的方式解决单例模式,此种方式可能是平时最少用到的。这种方式解决了最主要的;线程安全、自由串行化、单一实例。调用方式 ...

June 1, 2020 · 2 min · jiezi

JAVA设计模式理解与总结-单例模式工厂模式建造者模式

码了好几年代码的打字机器我,对于设计模式这个词,肯定是一点也不陌生,但是对于设计模式的理解,因为日常开发中,增删改查较多,使用设计模式思想来优化代码的机会就很少。也不乏在翻阅源码的时候,叹服于别人优秀高效的设计。所有今天抽出点时间,对设计模式做个归纳、记录,以便日后读到优秀的源码,可以自信的说,这**不就是那啥吗,我也会写~~~设计模式设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案 单例模式饿汉模式不管你需不需要,我都给你准备好,对于饿汉来说,心里踏实 饿汉模式很简单,提前提供实例对象 代码样例 public class SingleMan { private SingleMan() { } static { System.out.println("类加载"); } private static SingleMan instance = new SingleMan(); public static SingleMan getInstance() { return instance; } public void sayHello() { System.out.println("你好,相亲吗"); }}饿汉式与线程安全实例在类加载时实例化,有JVM保证线程安全。 虚拟机在编译加载某个类的时候,会将所有类变量(static)、静态代码块(static{})进行赋值。 虚拟机会在执行该操作时加锁,保证同一个类加载器下,一个类型只会初始化一次! 题外话: 类的加载时机JVM只在需要某个类或者使用Class.forName(className)强制加载类的时候才会被调用,如果只是声明某个类的引用,而没有创建对象则不会加载该类 懒汉模式懒汉模式,厨房有材料,鸡鸭鱼肉,饿得不行了,非吃不可了,才去做饭,此为懒汉 非线程安全的懒汉模式public class SingleMan { private SingleMan() { } static { System.out.println("类加载"); } private static SingleMan instacne = null; public static SingleMan getInstance() { if (null == instacne) { instacne = new SingleMan(); } return instacne; } public void sayHello() { System.out.println("你好,相亲吗"); }}线程安全的懒汉模式使用 双重检验锁 ...

May 29, 2020 · 3 min · jiezi

重学-Java-设计模式实战原型模式

作者:小傅哥博客:https://bugstack.cn 沉淀、分享、成长,让自己和他人都能有所收获!?一、前言老板你加钱我的代码能飞 程序员这份工作里有两种人;一类是热爱喜欢的、一类是仅当成工作的。而喜欢代码编程的这部分人会极其主动学习去丰富自己的羽翼,也非常喜欢对技术探索力求将学到的知识赋能到平时的业务需求开发中。对于这部分小伙伴来说上班写代码还能赚钱真的是幸福! 怎么成为喜欢编码都那部分人 无论做哪行那业你都喜欢,往往来自从中持续不断都获取成就感。就开发编程而言因为你的一行代码影响到了千千万万的人、因为你的一行代码整个系统更加稳定、因为你的一行代码扛过了所有秒杀等等,这样一行行的代码都是你日积月累学习到的经验。那如果你也想成为这样有成就感的程序员就需要不断的学习,不断的用更多的技能知识把自己编写的代码运用到更核心的系统。 方向不对努力白费 平常你也付出了很多的时间,但就是没有得到多少收益。就像有时候很多小伙伴问我,我是该怎么学一个我没接触过的内容。我的个人经验非常建议,先不要学太多理论性的内容,而是尝试实际操作下,把要学的内容做一些Demo案例出来。这有点像你买了个自行车是先拆了学学怎么个原理,还是先骑几圈呢?哪怕摔了跟头,但那都是必须经历后留下的经验。 同样我也知道很多人看了设计模式收获不大,这主要新人对没有案例或者案例不贴近实际场景没有学习方向导致。太空、太虚、太玄,让人没有抓手! 所以我开始编写以实际案例为着手的方式,讲解设计模式的文章,帮助大家成长的同时也让我自己有所沉淀! 二、开发环境JDK 1.8Idea + Maven涉及工程三个,可以通过关注公众号:bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)工程描述itstack-demo-design-4-00场景模拟工程,模拟在线考试题库抽提打乱顺序itstack-demo-design-4-01使用一坨代码实现业务需求,也是对ifelse的使用itstack-demo-design-4-02通过设计模式优化改造代码,产生对比性从而学习三、原型模式介绍 原型模式主要解决的问题就是创建重复对象,而这部分对象内容本身比较复杂,生成过程可能从库或者RPC接口中获取数据的耗时较长,因此采用克隆的方式节省时间。 其实这种场景经常出现在我们的身边,只不过很少用到自己的开发中,就像; 你经常Ctrl+C、Ctrl+V,复制粘贴代码。Java多数类中提供的API方法;Object clone()。细胞的有丝分裂。类似以上的场景并不少,但如果让你去思考平时的代码开发中,有用到这样的设计模式吗?确实不那么容易找到,甚至有时候是忽略了这个设计模式的方式。在没有阅读下文之前,也可以思考下哪些场景可以用到。 四、案例场景模拟 每个人都经历过考试,从纸制版到上机答题,大大小小也有几百场。而以前坐在教室里答题身边的人都是一套试卷,考试的时候还能偷摸或者别人给发信息抄一抄答案。 但从一部分可以上机考试的内容开始,在保证大家的公平性一样的题目下,开始出现试题混排更有做的好的答案选项也混排。这样大大的增加了抄的成本,也更好的做到了考试的公平性。 但如果这个公平性的考试需求交给你来完成,你会怎么做? 因为需要实现一个上机考试抽题的服务,因此在这里建造一个题库题目的场景类信息,用于创建;选择题、问答题。 1. 场景模拟工程itstack-demo-design-4-00└── src └── main └── java └── org.itstack.demo.design ├── AnswerQuestion.java └── ChoiceQuestion.java在这里模拟了两个试卷题目的类;ChoiceQuestion(选择题)、AnswerQuestion(问答题)。如果是实际的业务场景开发中,会有更多的题目类型,可以回忆一下你的高考试卷。2. 场景简述2.1 选择题public class ChoiceQuestion { private String name; // 题目 private Map<String, String> option; // 选项;A、B、C、D private String key; // 答案;B public ChoiceQuestion() { } public ChoiceQuestion(String name, Map<String, String> option, String key) { this.name = name; this.option = option; this.key = key; } // ...get/set}2.2 问答题public class AnswerQuestion { private String name; // 问题 private String key; // 答案 public AnswerQuestion() { } public AnswerQuestion(String name, String key) { this.name = name; this.key = key; } // ...get/set}以上两个类就是我们场景中需要的物料内容,相对来说比较简单。如果你在测试的时候想扩充学习,可以继续添加一些其他物料(题目类型)。五、用一坨坨代码实现今天的实现方式没有ifelse了,但是没有一个类解决不了的业务,只要你胆大! ...

May 29, 2020 · 5 min · jiezi

多例模式

上篇文章,我们说过了单例模式,有童鞋会问:有单例,是不是有多例?答案:是的,这篇文章,我们来聊一下多例模式。 多例模式,就是一个类有多个实例,而且该实例都是该类本身。这样的类叫做多例类,具有以下: 多例类可以有多个实例。多例类必须自己创建、管理自己的实例,并向外界提供自己的实例。简单啰嗦一句,跟普通我们new对象不一样,我们可以多次new对象,但是每次new的对象都是一个新的对象;而多例类里面所有的实例都是该类本身。 下面我们来看一下具体的代码实现:逻辑:CD工厂要不不同的内容授权给不同的工厂去生产:把CD1的内容让工厂1生产;CD2的内容让工厂2生产。这样可以减少CD工厂的数量,增加CD工厂的扩展性。 class CDFactory{ /** * 实例对象数组 * * @var array */ private static $_instances = []; /** * 构造函数私有,防止类可以通过 new 实例化 * * @access private * @return void */ private function __construct () { } /** * 私有化复制克隆方法,防止类别复制和克隆 * * @access private * @return void */ private function __clone () { } /** * 阻止实例被序列化 * * @access private * @return void */ private function __wakeup () { } /** * 定义获取对象实例的入口,返回该实例 * * @access public * @param string $name 实例化名字 * @return self */ public static function getInstance (string $name) { // 判断是否已经存在实例化对象 if (!isset(self::$_instances[$name])) { p('new intance:' . __CLASS__); // 不存在,则实例化一个 self::$_instances[$name] = new self(); } return self::$_instances[$name]; } /** * 此接口用来测试单例模式 - 改变 string 的值 * * @access public * @param string $string 值 * @return void */ public function setContent($string) { $this->string = $string; } /** * 此接口用来测试单例模式 - 输出 string 的值 * * @access public * @return void */ public function getContent() { p('$this->string',$this->string); }}调用的代码: ...

May 28, 2020 · 2 min · jiezi

javascript-设计模式修言小册干货长文建议收藏

前言最近拜读了一下修言大神的JavaScript 设计模式核⼼原理与应⽤实践, 对于现阶段的我,可以说受益匪浅,自己也学着总结下,分享下干货,力求共同进步! 在软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。 ——维基百科先提炼下,文章缺少小册前两章,概括来说: 技术寒冬,前端真的很缺人,经得起推敲的人太少;前端技术面很大,想把每一面都涵盖到很难,不建议大家死磕;追求极致设计,讲究道术结合;掌握核心科技,以‘不变’应万变;前端工程师,首先是软件工程师;这里强调一下以不变应万变的中不变的是什么,因为这关系到你的核心竞争力是什么在哪里。所谓‘不变的东西’说的驾驭技术的能力,具体来说分以下三个层次: 能用健壮的代码去解决具体问题;能用抽象的思维去应对复杂的系统;能用工程化的思想去规划更大规模的业务;这三种能力在你的成长过程中是层层递进的关系,而后两种能力可以说是对架构师的要求。能做到第一点,并且把它做到扎实、做到娴熟的人,已经堪称同辈楷模很多人缺乏的并不是这种高瞻远瞩的激情,而是我们前面提到的“不变能力”中最基本的那一点——用健壮的代码去解决具体的问题的能力。这个能力在软件工程领域所对标的经典知识体系,恰恰就是设计模式。所以说,想做靠谱开发,先掌握设计模式。 小册的知识体系与格局,用思维导图展示如下: 下面涉及到的是小册中细讲的设计模式; 目录:工厂模式单例模式原型模式修饰器模式适配器模式代理模式策略模式状态模式观察者模式迭代器模式工厂模式定义: 工厂模式其实就是将创建的对象的过程单独封装; 简单工厂模式结合定义我们来看一段需求,公司需要编写一个员工信息录入系统,当系统里面只创建自己的时候我们可以: const lilei = { name = 'lilei', age: 18, career: 'coder'}当然员工肯定不会是一个,并且会不断加入,所以使用构造函数写成: function User(name, age, career) { this.name = name; this.age = age; this.career = career;}const lilei = new User('lilei', 18, 'coder')const lilei = new User('hanmeimei', 20, 'product manager')// ...上面的代码其实就是构造器,关于构造器模式后面会有具体介绍,我们采用ES5的构造函数来实现,ES6的class其本质还是函数,class只不过是语法糖,构造函数,才是它的这面目。 需求继续增加,career字段能携带的信息有限,无法完整诠释人员职能,要给每个工种的用户添加上一个个性字段,来描述相应的职能。 function Coder(name, age){ this.name = name; this.age = age; this.career = 'coder'; this.work = ['敲代码', '摸鱼', '写bug'];}function ProductManager(name, age) { this.name = name; this.age = age; this.career = 'product manager'; this.work = ['订会议室', '写PRD', '催更']}function Factory(name, age, career) { switch(career) { case 'coder': return new Coder(name, age); break; case 'product manager': return new ProductManager(name, age); break; ... }}现在看至少我们不用操心构造函数的分配问题了,那么问题来了,大家都看到了省略号了吧,这就意味着每多一个工种就要手动添加一个类上去,假如有几十个工种,那么就会有几十个类?相对来说,我们还是需要不停的声明新的构造函数。 ...

November 5, 2019 · 3 min · jiezi

设计模式之备忘录模式

0x01.定义与类型定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。类型:行为型UML类图 基本代码实现/** * 发起人类 */public class Originator { /** * 状态编码 */ private String status; public Originator(String status) { this.status = status; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } /** * 创建备忘录 * @return */ public Memento createMemento() { return new Memento(this); } /** * 回滚 * @param memento */ public void restoreMemento(Memento memento) { this.status = memento.getStatus(); }}/** * 备忘录类 */public class Memento { private String status; public Memento(Originator originator) { this.status = originator.getStatus(); } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; }}/** * 备忘录管理类 */public class Caretaker { /** * 备忘录记录栈 */ private Stack<Memento> MEMENTO_STACK; public Caretaker() { MEMENTO_STACK = new Stack<>(); } /** * 添加一个备忘录 * @param memento */ public void addMemento(Memento memento) { MEMENTO_STACK.push(memento); } /** * 获取一个备忘录 * @return */ public Memento getMemento() { return MEMENTO_STACK.pop(); }}测试与应用/** * 测试与应用 */public class Test { public static void main(String[] args) { //备忘录管理 Caretaker caretaker = new Caretaker(); //发起人 Originator originator = new Originator("1"); //创建备忘录1 Memento memento1 = originator.createMemento(); caretaker.addMemento(memento1); //修改并创建备忘录2 originator.setStatus("2"); Memento memento2 = originator.createMemento(); caretaker.addMemento(memento2); //修改状态3 originator.setStatus("3"); System.out.println(originator.getStatus()); //回滚上一次 originator.restoreMemento(caretaker.getMemento()); System.out.println(originator.getStatus()); //回滚上一次 originator.restoreMemento(caretaker.getMemento()); System.out.println(originator.getStatus()); }}输出结果321备忘录模式角色介绍 ...

November 5, 2019 · 3 min · jiezi

单例模式和中介者模式

单例模式基本概念属于创建型模式,它提供了一种创建对象的方式。仅涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。类图 Singleton类称为单例类,通过使用private的构造函数确保在一个应用中只产生一个实例,并且是自行化实例的(在Singleton中自己使用 new Singleton()) 代码示例// 创建一个Singleton的类class SingleObject { // 使构造函数私有化 private constructor() {} // 获取唯一可用的对象 private static sing: SingleObject static GetInstance(): SingleObject { if(this.sing){ this.sing = new SingleObject() } return this.sing } public GetUserInfo():string{ let str: string="你好啊" return str } } const sing1 = SingleObject.GetInstance()console.log(117,sing1) // Declaration or statement expected 需要声明 优点在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要 比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一 个单例对象,然后用永久驻留内存的方式来解决(在Java EE中采用单例模式时需要注意JVM 垃圾回收机制)。避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在 内存中,避免对同一个资源文件的同时写操作。单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单 例类,负责所有数据表的映射处理。缺点单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途 径可以实现。单例模式为什么不能增加接口呢?因为接口对单例模式是没有任何意义的,它 要求“自行实例化”,并且提供单一实例、接口或抽象类是不可能被实例化的。当然,在特殊 情况下,单例模式可以实现接口、被继承等,需要在系统开发中根据环境判断。单例模式对测试是不利的。在并行开发环境中,如果单例模式没有完成,是不能进行 测试的,没有接口也不能使用mock的方式虚拟一个对象。单例模式与单一职责原则有冲突。一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中。应用场景要求生成唯一序列号的环境;在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,可以 不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源;需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当 然,也可以直接声明为static的方式)。中介者模式定义用一个中介对象封装一系列的对象交互,中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立的改变它们之间的交互 角色Mediator(抽象中介者):定义一个接口,该接口用于各同事对象之间进行通信ConcreateMediator(具体中介者):是抽象中介者的子类,通过协调各个同事对象来实现协作行为,维持了对各个同事对象的引用Colleague(抽象同事类):它定义各个同事类共有的方法,并声明一些抽象方法供子类实现,维持了一个对抽象中介者的引用,其子类可以通过该引用与中介者通信ConcreateColleague(具体同事类):它的抽象同事类的子类,每一个同事对象在需要和其他同事对象通信时,先于中介者通信,通过中介者间接完成与其他同事类的通信,在具体同事类中实现了在抽象同事类中声明的抽象方法类图 代码示例// 抽象中介者abstract class Media{ abstract contact(message:string,person:Human): void}// 抽象同事类abstract class Human { name: string media: Media constructor(name: string, media: Media) { this.name = name; this.media = media; }}// 具体的同事类// 房主类class HouseOwner extends Human { contact(message:string){ console.log(`房主${this.name}发送消息${message}`) this.media.contact(message,this) } getMessage(message:string){ console.log(`房主${this.name}收到消息${message}`) }}// 租客类class Tenant extends Human { contact(message: string) { console.log(`租客 ${this.name} 发送消息 ${message}`); this.media.contact(message, this); } getMessage(message: string) { console.log(`租客 ${this.name} 收到消息 ${message}`); }}// 具体中介者类class ConcreateMedia extends Media { private tenant: Tenant; private houseOwner: HouseOwner; setTenant(tenant: Tenant) { this.tenant = tenant; } setHouseOwner(houseOwner: HouseOwner) { this.houseOwner = houseOwner; } // 由中介者来设置同事对象之间的联系关系 contact(message: string, person: Human) { console.log('中介传递消息'); if (person === this.houseOwner) { this.tenant.getMessage(message); } else { this.houseOwner.getMessage(message); } }}const media = new ConcreateMedia()const houseOwner = new HouseOwner('房东叔叔',media)const tenant = new Tenant('红红',media)media.setHouseOwner(houseOwner)media.setTenant(tenant)tenant.contact('想租房')houseOwner.contact('有房子出租')// 租客 红红 发送消息 想租房// 中介传递消息// 房主 房东叔叔 收到消息 想租房// 房主 房东叔叔 发送消息 有房子出租// 中介传递消息// 租客 红红 收到消息 有房子出租优点简化了对象之间的关系,将系统的各个对象之间的相互关系进行封装,将各个同事类解耦,使系统变为松耦合提高系统的灵活性,使各个同事对象独立并且易于复用缺点中介者模式中,中介者承担了较多的责任,一旦中介者对象出现问题,整个系统会受到影响新增一个同事类的时候,需要修改抽象中介者类和具体中介者类应用场景中介者模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是:在类图中出现蜘蛛网状结构。这种情况考虑使用中介者模式,将蜘蛛网状转化为星状。下几个是生活和开发中碰到的例子: ...

November 5, 2019 · 1 min · jiezi

访问者模式的实现

访问者模式的实现访问者模式就是针对不同的资源设置不同的访问权限, 反转这访问权限的设置位置,从而达到不修改资源来控制访问权限的目的. 先设置一个元素材资源和元访问权限public class unionLevel { public String getLevelName(unionVisitor visitor){ return "see union level"; };}public interface unionVisitor { /** * 看第一级素材 * @return */ default String seeLevelOne(unionLevel level){ return level+" forbidden"; } /** * level two * @return */ default String seeLevelTwo(unionLevel level){ return level+" forbidden"; } /** * level three * @return */ default String seeLevelThree(unionLevel level) { return level+" forbidden"; }}设置多级素材继承元素材public class LevelOne extends unionLevel{ @Override public String getLevelName(unionVisitor visitor) { System.out.println(visitor.seeLevelOne(this)); return super.getLevelName(visitor); } @Override public String toString() { return "levelone"; }}设置多级权限实现元权限public class VisitorOne implements unionVisitor{ /** * 看第一级素材 * * @return */ @Override public String seeLevelOne(unionLevel level) { return "VisitorOne can see "+level; }}写个测试类(其他元素和素材照着上面demo写就行)public class start { public static void main(String[] args) { LevelTwo two = new LevelTwo(); two.getLevelName(new VisitorOne()); two.getLevelName(new VisitorTwo()); two.getLevelName(new VisitorThree()); }}总结平常不怎么喜欢写总结的,但是说要是使用的时候还是会去翻一下他的定义。以免自己弄错了都不知道,其实对于访问者模式来说,最大的好处就是对权限这边的解放(不过你要是资源级别会随意变动而权限设置不会随便变动的话,可以将这个设计反过来。毕竟设计是死的而人是活的。肯定要写成对实现更加方便的代码出来) ...

November 5, 2019 · 2 min · jiezi

设计模式之观察者模式

0x01.定义与类型定义:定义了对象之间的一对多依赖,让多个观察者对象同时监听某一个主题对象,当主题对象发生变化时,它的所有依赖者(观察者)都会收到通知并更新。类型:行为型UML类图 示例代码实现/** * 被观察实例抽象定义 */public abstract class Subject { /** * 观察者数组 */ protected List<Observer> observers; /** * 添加一个观察者 * @param observer */ public abstract void add(Observer observer); /** * 删除一个观察者 * @param observer */ public abstract void remove(Observer observer); /** * 通知观察者 */ public abstract void notifyObserver();}/** * 观察者接口 */public interface Observer { void response();}/** * 被观察的实例 */public class ConcreteSubject extends Subject { public ConcreteSubject() { super.observers = new ArrayList<>(); } @Override public void add(Observer observer) { this.observers.add(observer); } @Override public void remove(Observer observer) { this.observers.remove(observer); } @Override public void notifyObserver() { for (Observer observer : this.observers) { observer.response(); } }}/** * 观察者1 */public class ConcreteObserver1 implements Observer { @Override public void response() { System.out.println("通知观察者1"); }}/** * 观察者2 */public class ConcreteObserver2 implements Observer { @Override public void response() { System.out.println("通知观察者2"); }}测试与应用/** * 测试与应用 */public class Test { public static void main(String[] args) { //创建实例 Subject subject = new ConcreteSubject(); //创建观察者对象 Observer observer1 = new ConcreteObserver1(); Observer observer2 = new ConcreteObserver2(); //添加观察者对象 subject.add(observer1); subject.add(observer2); //通知观察者 subject.notifyObserver(); }}输出结果通知观察者1通知观察者2角色介绍: ...

November 2, 2019 · 2 min · jiezi

JavaScript中发布订阅模式观察者模式

发布/订阅模式的前身-观察者模式观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新。观察者模式属于行为型模式,行为型模式关注的是对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯。 观察者模式有一个别名叫“发布-订阅模式”,或者说是“订阅-发布模式”,订阅者和订阅目标是联系在一起的,当订阅目标发生改变时,逐个通知订阅者。 什么是发布/订阅模式其实24种基本的设计模式中并没有发布订阅模式,上面也说了,他只是观察者模式的一个别称。但是经过时间的沉淀,似乎他已经强大了起来,已经独立于观察者模式,成为另外一种不同的设计模式。在现在的发布订阅模式中,称为发布者的消息发送者不会将消息直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件,称为消息代理或调度中心或中间件,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地分发它们给订阅者。 根本作用广泛应用于异步编程中(替代了传递回调函数)对象之间松散耦合的编写代码基本案例介绍背景:成都老妈兔头真香,买的人太多需要预定才能买到,所以顾客就等于了订阅者,订阅老妈兔头。而老妈兔头有货了得通知顾客来买啊,不然没有钱赚,得通知所有的订阅者有货了来提兔头,这时老妈兔头这家店就是发布者。 /*兔头店*/ var shop={ listenList:[],//缓存列表 addlisten:function(fn){//增加订阅者 this.listenList.push(fn); }, trigger:function(){//发布消息 for(var i=0,fn;fn=this.listenList[i++];){ fn.apply(this,arguments); } }}/*小明订阅了商店*/shop.addlisten(function(taste){ console.log("通知小明,"+taste+"味道的好了");});/*小龙订阅了商店*/shop.addlisten(function(taste){ console.log("通知小龙,"+taste+"味道的好了");});/*小红订阅了商店*/shop.addlisten(function(taste){ console.log("通知小红,"+taste+"味道的好了");}); // 发布订阅shop.trigger("中辣");//console通知小明,中辣味道的好了通知小龙,中辣味道的好了通知小红,中辣味道的好了案例升级上面的案例存在问题,因为在触发的时候是将所以的订阅都触发了,并没有区分和判断,所以需要一个Key来区分订阅的类型,并且根据不同的情况触发。而且订阅是可以取消的。 升级思路: 创建一个对象(缓存列表)addlisten方法用来把订阅回调函数fn都加到缓存列表listenList中trigger方法取到arguments里第一个当做key,根据key值去执行对应缓存列表中的函数remove方法可以根据key值取消订阅/*兔头店*/ var shop={ listenList:{},//缓存对象 addlisten:function(key,fn){ // 没有没有key给个初值避免调用报错 if (!this.listenList[key]) { this.listenList[key] = []; } // 增加订阅者,一个key就是一种订阅类型 this.listenList[key].push(fn); }, trigger:function(){ const key = Array.from(arguments).shift() const fns = this.listenList[key] // 这里排除两种特殊情况,第一种为触发的一种从未订阅的类型,第二种订阅后取消了所有订阅的 if(!fns || fns.length===0){ return false; } // 发布消息,触发同类型的所有订阅, fns.forEach((fn)=>{ fn.apply(this,arguments); })/* for(var i=0,fn;fn=fns[i++];){ fn.apply(this,arguments); } */ }, remove:function(key,fn){ var fns=this.listenList[key];//取出该类型的对应的消息集合 if(!fns){//如果对应的key没有订阅直接返回 return false; } if(!fn){//如果没有传入具体的回掉,则表示需要取消所有订阅 fns && (fns.length=0); }else{ for(var l=fns.length-1;l>=0;l--){//遍历回掉函数列表 if(fn===fns[l]){ // 这里是传入地址的比较,所以不能直接用匿名函数了 fns.splice(l,1);//删除订阅者的回掉 } } } }}function xiaoming(taste){ console.log("通知小明,"+taste+"味道的好了");}function xiaolong(taste){ console.log("通知小龙,"+taste+"味道的好了");}function xiaohong(taste){ console.log("通知小红,"+taste+"味道的好了");}// 小明订阅了商店shop.addlisten('中辣',xiaoming);shop.addlisten('特辣',xiaoming);// 小龙订阅了商店shop.addlisten('微辣',xiaolong);// 小红订阅了商店shop.addlisten('中辣',xiaohong);// 小红突然不想吃了shop.remove("中辣",xiaohong);// 中辣口味做好后,发布订阅shop.trigger("中辣");shop.trigger("微辣");shop.trigger("特辣"); ...

November 2, 2019 · 1 min · jiezi

设计模式之模板方法模式

0x01.定义与类型定义:定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。比如定义一个操作中的算法的骨架,将步骤延迟到子类中。模板方法使得子类可以再不改变算法结构的情况下,重新定义算法的某些步骤类型:行为型UML类图 样例代码/** * 模板方法类 */public abstract class ATemplate { /** * 模板方法 */ public void templateMethod() { before(); doAction(); after(); } /** * 钩子函数 * 一个空的方法 */ protected void before(){} /** * 抽象方法 * 业务逻辑 */ public abstract void doAction(); /** * 具体方法 */ private void after() { System.out.println("after!"); }}/** * 具体的实现类 */public class BusinessEntity extends ATemplate { @Override protected void before() { super.before(); System.out.println("before"); } @Override public void doAction() { System.out.println("doAction"); }}测试与应用类public class Test { public static void main(String[] args) { ATemplate template = new BusinessEntity(); template.templateMethod(); }}输出结果beforedoActionafter!角色介绍 ...

October 17, 2019 · 2 min · jiezi

设计模式之代理模式

代理模式0x01.定义与类型定义:为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用,可去掉功能服务或增加额外的服务。类型:结构型几种代理方式: 远程代理--为不同地理的对象,提供局域网代表对象---通过远程代理来模拟各个店铺的监控虚拟代理--根据需要将资源消耗很大的对象进行延迟-真正需要的时候进行创建--比如说先加载文字-图片是虚拟的-再加载保护代理--控制一个对象的访问权限--权限控制智能引用代理--火车票代售处0x02.适用场景保护目标对象增强目标对象0x03.优缺点优点代理模式能将代理对象与真实被调用的目标对象分离一定程度上降低了系统的耦合度,扩展性好保护目标对象增强目标对象缺点代理模式会造成系统设计中类的数据增加在客户端和目标对象增加一个代理对象,会造成请求处理速度缓慢增加了系统的复杂度0x04.扩展1.静态代理定义:通过在代码中显示定义了一个业务实现类的代理,在代理类中实现了同名的被代理类的方法,通过调用代理类的方法,实现对被代理类方法的增强。代理和被代理对象在代理在代理之前是确定的,他们都是实现的相同的接口或者继承相同的抽象类静态代理UML类图 代码实现/** * 被代理的接口类 * @author zhiyuan.shen */public interface Subject { /** * 具体方法 */ void doAction();}/** * @author zhiyuan.shen */public class RealSubject implements Subject { @Override public void doAction() { System.out.println("service impl class."); }}/** * 代理类 * @author zhiyuan.shen */public class Proxy implements Subject { private Subject subject; public Proxy(Subject subject) { this.subject = subject; } @Override public void doAction () { System.out.println("before"); subject.doAction(); System.out.println("after"); }}测试与应用类/** * @author zhiyuan.shen */public class Test { public static void main(String[] args) { //创建服务类 RealSubject realSubject = new RealSubject(); //自己执行方法 realSubject.doAction(); System.out.println("----------"); //创建代理类 Proxy proxy = new Proxy(realSubject); //代理执行 proxy.doAction(); }}输出结果service impl class.----------beforeservice impl class.after静态代理角色介绍 ...

October 16, 2019 · 3 min · jiezi

工厂模式和策略模式

什么是设计模式?设计模式是对面向对象设计中反复出现的问题的解决方案。 为什么要用设计模式?使用设计模式是为了是代码更容易被他人理解、同时使代码的更加的可维护、可扩展、可复用。 设计模式的原则开放 封闭原则 : 开发扩展 封闭修改依赖倒置原则 : 高层模块不应该依赖低层模块,两个都应该依赖抽象抽象不应该依赖细节。细节应该依赖抽象里氏代换原则: 子类型必须能够替换掉它们的父类型接口隔离原则迪米特法则又称最少知道原则合成复用原则设计模式的类型: 创建型模式: 这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用new运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。 工厂模式抽象工厂模式单例模式建造者模式原型模式结构型模式: 这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。 适配器模式桥接模式过滤器模式组合模式装饰器模式外观模式享元模式代理模式行为型模式: 责任链模式命令模式解释器模式迭代器模式中介者模式备忘录模式观察者模式状态模式空对象模式策略模式模板模式访问者模式简单工厂 优点: 将创建产品对象封装起来,后期如果需要修改类名的时候,仅仅需要修改工厂类的类名就可以。 缺点: 违背了开放-封闭原则,当我们要新增一个OPPO手机的时候,需要修改工厂方法。 工厂方法模式: 定义一个用于创建对象的接口,让子类决定实例化哪一类。工厂方法使一个类的实例化延迟到其子类。 优点: 客户端使用对象,只需要知道其名称就可以了。扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以了。缺点: 每次增加一个产品时,都需要增加一个具体类和对象实现工厂。 抽象工厂模式: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂结构图: 抽象工厂优化结构图 策略模式:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。 工厂方法模式 和 抽象工厂模式区别工厂方法模式是用一个 工厂类 来创建 一个 对象。抽象工厂模式是用一个 工厂类 来创建 多个 对象。因为这些对象属于同一个 产品线有一个 手机工厂, 可以用来生产手机。生产一部手机需要: 操作系统, CPU, 内存 等等: 如果要支持生产以前的 诺基亚功能机和现在的 安卓智能手机,那么他们所需的 操作系统, CPU, 内存都是不同的。那就可以创建两个抽象工厂: 诺基亚Factory 和 安卓Factory: 参考: 《大话设计模式》https://book.douban.com/subje... 设计模式 菜鸟教程: https://www.runoob.com/design... ...

October 15, 2019 · 1 min · jiezi

4设计模式之抽象工厂

1、抽象工厂定义抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口。无须指定它们具体的类。适用场景:1) 客户端不依赖于产品类实例如何被创建、实现等细节2) 强调一系列相关的产品对象(属于同一个产品族)一起使用创建对象对象需要大量重复代码3) 提供一个产品类的库,所有产品以同样的接口出现,从而使客户端不依赖于具体的实现优点:1) 具体产品在应用层代码隔离,无须关心创建细节2) 将一个系列的产品族统一到一起创建缺点:1) 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的集合2) 增加了系统的抽象性和理解难度下图是抽象工厂的产品族和产品等级结构。同一行是一个产品族,比如同属美的公司生产的冰箱、空调。而同一列则是同一类产品,比如美的的空调、海尔的空调。工厂方法模式针对的产品等级结构,而抽象工厂模式针对的是产品族,这是工厂方法和抽象工厂模式最大的区别。 2、代码演示public abstract class Video { public abstract void produce();}public class JavaVideo extends Video { @Override public void produce() { System.out.println("录制Java课程视频"); }}public class PythonVideo extends Video { @Override public void produce() { System.out.println("录制Python课程视频"); }}public abstract class Article { public abstract void produce();}public class JavaArticle extends Article { @Override public void produce() { System.out.println("编写Java课程手记"); }}public class PythonArticle extends Article { @Override public void produce() { System.out.println("编写Python课程手记"); }}public interface CourseFactory { Video getVideo(); Article getArticle();}public class JavaCourseFactory implements CourseFactory { @Override public Video getVideo() { return new JavaVideo(); } @Override public Article getArticle() { return new JavaArticle(); }}public class PythonCourseFactory implements CourseFactory { @Override public Video getVideo() { return new PythonVideo(); } @Override public Article getArticle() { return new PythonArticle(); }}public class Test { public static void main(String[] args) { CourseFactory courseFactory = new JavaCourseFactory(); Video video = courseFactory.getVideo(); Article article = courseFactory.getArticle(); video.produce(); article.produce(); }}

October 5, 2019 · 1 min · jiezi

5设计模式之建造者

1、建造者定义将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。用户只需要指定需要创建的类型就可以得到它们,建造过程及细节不需要知道。适用场景:1) 如果一个对象具有非常复杂的内部结构(很多属性)2) 想把复杂对象的创建和使用分离优点:1) 封装性好,创建和使用分离2) 扩展性好、建造类之间独立,一定程度上解耦缺点:1) 产生多余的Builder对象2) 产品内部发生变化,建造者都要修改,成本较大2、代码演示public class Course { private String courseName; private String coursePPT; private String courseVideo; private String courseArticle; private String courseQA; public Course(CourseBuilder courseBuilder) { this.courseName = courseBuilder.courseName; this.coursePPT = courseBuilder.coursePPT; this.courseVideo = courseBuilder.courseVideo; this.courseArticle = courseBuilder.courseArticle; this.courseQA = courseBuilder.courseQA; } public static class CourseBuilder{ private String courseName; private String coursePPT; private String courseVideo; private String courseArticle; private String courseQA; public CourseBuilder buildCourseName(String courseName){ this.courseName = courseName; return this; } public CourseBuilder buildCoursePPT(String coursePPT) { this.coursePPT = coursePPT; return this; } public CourseBuilder buildCourseVideo(String courseVideo) { this.courseVideo = courseVideo; return this; } public CourseBuilder buildCourseArticle(String courseArticle) { this.courseArticle = courseArticle; return this; } public CourseBuilder buildCourseQA(String courseQA) { this.courseQA = courseQA; return this; } public Course build(){ return new Course(this); } }}public class Test { public static void main(String[] args) { Course course = new Course.CourseBuilder() .buildCourseName("Java设计模式精讲") .buildCoursePPT("Java设计模式精讲PPT") .buildCourseVideo("Java设计模式精讲视频").build(); System.out.println(course); Set<String> set = ImmutableSet.<String>builder().add("a").add("b").build(); System.out.println(set); }}

October 5, 2019 · 1 min · jiezi

3设计模式之工厂模式

1、工厂方法定义定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。适用场景:1) 创建对象需要大量重复的代码2) 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节3) 一个类通过其子类来指定创建哪个对象优点:1) 用户只需要关心所需产品对应的工厂,无须关心创建细节2) 加入新产品符合开闭原则,提高可扩展性缺点:1) 类的个数容易过多,增加复杂度2) 增加了系统的抽象性和理解难度2、代码演示 public abstract class Video { public abstract void produce();}public class PythonVideo extends Video { @Override public void produce() { System.out.println("录制Python课程视频"); }}public class JavaVideo extends Video { @Override public void produce() { System.out.println("录制Java课程视频"); }}public abstract class VideoFactory { public abstract Video getVideo();}public class PythonVideoFactory extends VideoFactory { @Override public Video getVideo() { return new PythonVideo(); }}public class JavaVideoFactory extends VideoFactory { @Override public Video getVideo() { return new JavaVideo(); }}public class Test { public static void main(String[] args) { VideoFactory videoFactory = new PythonVideoFactory(); Video video = videoFactory.getVideo(); video.produce(); videoFactory = new JavaVideoFactory(); video = videoFactory.getVideo(); video.produce(); }}

October 5, 2019 · 1 min · jiezi

2设计模式之简单工厂模式

1、简单工厂定义由一个工厂对象决定创建哪一种产品类的实例,不属于GOF23种设计模式。适用场景1) 工厂类负责创建的对象比较少2) 客户端(应用层)只知道传入工厂类的参创建对象(逻辑)不关心优点:只需要传入一个正确的参数,就可以获取你所需要的对象而无需知道其创建细节。缺点:工厂类的职责相对过重,增加新的产品,需要修改工厂类的判断逻辑,违背开闭原则。2、代码演示public abstract class Video { public abstract void produce();}public class JavaVideo extends Video { @Override public void produce() { System.out.println("录制Java课程视频"); }}public class PythonVideo extends Video { @Override public void produce() { System.out.println("录制Python课程视频"); }}public class VideoFactory { public Video getVideo(Class c){ Video video = null; try { video = (Video) Class.forName(c.getName()).newInstance(); } catch (Exception e) { e.printStackTrace(); } return video; } public Video getVideo(String type){ if("java".equalsIgnoreCase(type)){ return new JavaVideo(); }else if("python".equalsIgnoreCase(type)){ return new PythonVideo(); } return null; }}public class Test { public static void main(String[] args) { VideoFactory videoFactory = new VideoFactory(); Video video = videoFactory.getVideo("java"); if(video == null){ return; } video.produce(); videoFactory = new VideoFactory(); video = videoFactory.getVideo(JavaVideo.class); if(video == null){ return; } video.produce(); }}

October 4, 2019 · 1 min · jiezi

1设计模式之软件设计七大原则

1、开闭原则1.1、定义一个软件实体如类、模块和函数应该`对扩展开放,对修改关闭`。用抽象构建框架,用实现扩展细节。优点:提高软件系统的可复用性以及可维护性1.2、代码演示public interface ICourse { Integer getId(); String getName(); Double getPrice();}public class JavaCourse implements ICourse{ private Integer Id; private String name; private Double price; public JavaCourse(Integer id, String name, Double price) { this.Id = id; this.name = name; this.price = price; } public Integer getId() { return this.Id; } public String getName() { return this.name; } public Double getPrice() { return this.price; }}// 如果需要在原有功能基础上添加一个获取打折价格的功能,开闭原则建议不要修改原有接口,这里可以继承原有JavaCourse类,// 在原有功能之上扩展public class JavaDiscountCourse extends JavaCourse { public JavaDiscountCourse(Integer id, String name, Double price) { super(id, name, price); } public Double getDiscountPrice(){ return super.getPrice()*0.8; }}2、开闭原则2.1、定义`高层模块不应该依赖低层模块`,二者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。针对接口编程,不要针对实现编程。优点:可以减少类之间的耦合性,提高系统的稳定性,提高代码可读性和可维护性,可降低修改程序所造成的风险。2.2、代码演示 ...

October 4, 2019 · 2 min · jiezi

依赖注入dependency-injection最通俗的讲解

这篇文章解释了什么是依赖注入(又称控制反转),以及它如何改善定义业务逻辑的代码。 服务和依赖服务可以是您编写的类,也可以是来自导入库的类。例如,它可以是一个 logger 或一个 database connection。因此,您可以编写一个无需任何外部帮助即可单独运行的服务,但也可能您会很快您会达到一个点,即其中一个服务将不得不使用另一个服务的代码的地步。 让我们看一个小的例子 我们将创建一个EmailSender。此类将用于发送电子邮件。它必须在数据库中写入已发送电子邮件的信息,并记录可能发生的错误。 EmailSender 将依赖于其他三项服务:用于发送电子邮件的 SmtpClient,用于与数据库交互的 EmailRepository 以及用于记录错误的 Logger。 通常情况下我们会怎么实现呢? 1.EmailSender 的三个依赖关系被声明为属性。依赖项注入的思想是,EmailSender不应该负责创建其依赖项,它们应该从外部注入。对EmailSender来说,其配置的详细信息应该是未知的。 interface SmtpClientInterface { send(toName: string, toEmail: string, subject: string, message: string)}interface EmailRepositoryInterface { insertEmail(address: string, email: Email, status: string) updateEmailStatus(id: number, status: string)}interface LoggerInterface { error(message: string)}class EmailSender { client: SmtpClientInterface repo: EmailRepositoryInterface logger: LoggerInterface send(user: User, email: Email) { try { this.repo.insertEmail(user.email, email, "sending") this.client.send(user.email, user.name, email.subject, email.message) this.repo.updateEmailStatus(email.id, "sent") } catch(e) { this.logger.error(e.toString()) } }}2.使用 setter,您可以在EmailSender上添加setSmtpClient(),setEmailRepository()和setLogger()方法。 ...

September 30, 2019 · 8 min · jiezi

观察者模式从公众号群发说起

每个人应该都订阅了不少微信公众号,那你有没有注意到微信公众号的消息呢?你订阅的公众号号主每发布一篇文章,你都会主动的接收到文章的推送,并不需要你点开每个订阅的公众号一一查看有没有更新,是不是觉得有点意思?感兴趣?那就接着往下看吧,因为接下来我们要模拟公众号群发的场景。 要模拟公众号群发,首先需要简单的了解一下公众号的特点,对于公众号的特点,我总结了以下三点: 每个公众号会有多名订阅者,公众号跟订阅者在某种层面上是一对多的关系只有订阅者才能在公众号发布新文章时,会及时接收到推送通知,没有订阅公众号的阅读者不会接收到文章推送通知。每个订阅者都依赖于公众号号主,只有公众号号主发布文章,订阅者才有文章查看现在业务场景我们大概知道了,那就开始动手编写我们的业务吧,我们先从公众号号主开始。 对于公众号号主,我们先理解一下公众号特点的第二点:只有订阅者才能在公众号发布新文章时,会及时接收到推送通知,没有订阅公众号的阅读者不会接收到文章推送通知。这个特点说明在公众号号主这边维护者订阅者的列表,在每次发布文章时会通知列表中的每一个订阅者告诉他们有新文章了。如果号主没有订阅者列表,那怎么知道需要通知哪些人呢?对于这个订阅者列表,号主肯定有增删的权利,毕竟这个公众号你说了算。根据上面分析的,我们给号主做出一个抽象,我们建立一个抽象的Author类。Author类具体设计如下: /** * 号主抽象类 */public interface Author { // 添加关注者 void addReader(Reader reader); // 删除关注者 void deleteReader(Reader reader); // 通知关注者 void notifyReader(); // 写文章 void writeArticle(String article);}在我们的场景中号主主要有添加订阅者、删除订阅者、通知订阅者和写文章的功能,号主有了,接下来就是我们的订阅者,订阅者在我们的场景中就比较简单了,只有一个阅读的功能,我们定义一个阅读者抽象类Reader,Reader类的具体设计如下: /** * 阅读者接口 */public interface Reader { // 阅读文章 void reader(String authorName,String article);}号主和阅读者的接口都定义好了,下面我们就需要真正的号主和订阅者了。我们建立我们第一个号主平头哥PingtougeAuthor,PingtougeAuthor类的设计如下: /** * @author 平头哥 * @title: PingtougeAuthor * @projectName observer * @description: 号主平头哥 * @date 2019/9/1817:50 */public class PingtougeAuthor implements Author{ // 订阅者列表 private Vector<Reader> readers ; // 作者名称 private String name; // 文章 private String article; public PingtougeAuthor(String name){ this.name = name; this.readers = new Vector<>(); } /** * 添加关注者 * @param reader */ @Override public void addReader(Reader reader) { if (readers.contains(reader)) return; readers.add(reader); } /** * 移除关注者 * @param reader */ @Override public void deleteReader(Reader reader) { readers.remove(reader); } /** * 通知关注者 */ @Override public void notifyReader() { for (Reader reader:readers){ reader.reader(name,article); } } /** * 写文章 * @param article */ @Override public void writeArticle(String article){ this.article = article; notifyReader(); }}我们在建立王山、张三、李四三个订阅者,他们的具体设计如下: ...

September 20, 2019 · 2 min · jiezi

快速理解-SOLID-面向对象设计依赖倒置原则

快速理解 SOLID (面向对象设计)——依赖倒置原则在程序设计领域, SOLID(单一功能、开闭原则、里氏替换、接口隔离以及依赖反转),指代了面向对象编程和面向对象设计的五个基本原则。当这些原则被一起应用时,它们使得一个程序员开发一个容易进行软件维护和扩展的系统变得更加可能。1. 依赖倒置原则1.1 依赖倒置原则 的定义一个方法应该遵从“依赖于抽象而不是一个实例” 1.2 依赖倒置原则 解决了什么问题一开始类A依赖于类B,由于需求发生了改变。要将类A依赖于类C,则我们需要修改类A依赖于类B的相关代码,这样会对程序产生不好的影响。假如需求又发生了改变,我们又需要修改类A的代码。 1.3 依赖倒置原则 举个例子public class UserService { private Plaintext plaintext; // 明文登录注册 public void register(){ Plaintext.register(); // 调用明文的注册方法 } public void login(){ Plaintext.login(); // 调用明文的登录方法 }}上面的例子可以看出,UserService类依赖于Plaintext类。有一天,由于使用明文登录注册不安全,需求改为使用密文登录注册。我们可以怎么办? //不符合 依赖倒置原则public class UserService { // private Plaintext plaintext; private Ciphertext ciphertext; // 密文登录注册 public void register(){ // Plaintext.register(); Ciphertext.register(); // 调用密文的注册方法 } public void login(){ // Plaintext.login(); Ciphertext.login(); // 调用密文的登录方法 }}在上面的例子,修改一个需求几乎将整个UserService类都修改了一遍,这不但麻烦,而且会给程序带来很多风险。所以上面的例子不符合依赖倒置原则。 ...

September 8, 2019 · 1 min · jiezi