关于设计模式:Java单例kotlin单例你真的会用单例么反正我面试过的人会的没几个

前言作为一家公司的Android技术主管,面试是一件比拟爽的事,一般来说我面到的都是程度不如我的(次要公司面试岗位不是很高,一般来说是中级或高级工程师),那么作为主管的我,对于人员的筛选上,设计模式比拟问的多。然而真正能说的出设计模式的人少之又少。很难让我称心。尤其是及其罕用的单例模式。 单例是什么?是一种对象创立模式,能够确保我的项目中一个类只产生一个实例。 益处对于频繁应用的对象能够缩小创建对象所破费的工夫,这对于重量级对象来说,几乎是福音。因为new的缩小,对系统内存应用频率也会升高,缩小GC的压力,并缩短GC进展工夫,这也会缩小Android我的项目的UI卡顿。 java的单例及其波及的知识点饿汉模式public class TestSingleton { private static final TestSingleton testSingleton = new TestSingleton(); private TestSingleton(){ } public static TestSingleton getInstance(){ return testSingleton; }}细节我就不多写了,大家都应该晓得,构造函数为private,用getInstance来获取实例 懒汉模式public class TestSingleton { private static TestSingleton testSingleton; private TestSingleton(){ } public static TestSingleton getInstance(){ if(testSingleton==null){ testSingleton = new TestSingleton(); } return testSingleton; }}比饿汉式的长处在于用时再加载,比拟重量级的单例,就不实用与饿汉了。 线程平安的懒汉模式public class TestSingleton { private static TestSingleton testSingleton; private TestSingleton(){ } public static TestSingleton getInstance(){ if(testSingleton==null){ synchronized (TestSingleton.class){ testSingleton = new TestSingleton(); } } return testSingleton; }}能够看到的是比下面的单例多了一个对象锁,着能够保障在创建对象的时候,只有一个线程可能创建对象。 ...

May 18, 2021 · 3 min · jiezi

关于设计模式:19-设计模式观察者模式下

上一篇说到了观察者模式较为传统的用法,这篇筹备分享点风行的,不过在开始新内容之前,咱们无妨先思考一下两种场景,一个是报社订阅报纸,另一个是在黑板上发布告,都是典型观察者模式利用场景,二者有何不同? 报社订阅报纸,订阅者须要到报社注销交钱,而后报社才会每次有新报纸时告诉到订阅者。而在黑板上发布告,公布的人不晓得谁会看到,看到的人也不晓得是谁收回的,而事实上,看到布告的人也可能只是偶尔的机会瞟了一眼黑板而已。能够看到,二者有显著的区别。前者,观察者必须要注册到被观察者上能力接管告诉;而后者,观察者和被观察者之间是互相齐全生疏的。回顾一下咱们在上一篇中举的例子,不难发现它其实相似第二种场景,狗叫并不知道谁会听见,而听的人也不是为了听狗叫,他仅仅是在关注外界的动静,恰好听到了狗叫而已。但咱们采纳的是相似第一种场景的解决形式,显然并不适合。因而,也就自然而然的留下了两个问题: dog.AddObserver(...)真的适合吗?理论生存中,狗真的有这种能力吗?咱们晓得C#中不反对多继承,如果Dog自身继承自Animal的基类,如果同时作为被观察者,除了用上述演进一的实现,还能如何实现?针对这两个问题,该怎么解决了?无妨再回顾一下之前学过的设计准则,看看哪里能够寻找突破口。 一番考虑不难发现,主题类违反了合成复用准则,也就是咱们常说的,HAS A比IS A更好。既然晓得HAS A更好,咱们为什么非得通过继承来实现性能的复用呢?更何况咱们继承的还是个一般类。 演进四-事件总线基于这种思路,咱们能够试着把继承改成组合,不过在这之前,咱们无妨一步到位,罗唆再为Subject类定义一个形象的接口,省得看着不难受,毕竟面向形象编程嘛: public interface ISubject{ void AddObserver(IObserver observer); void RemoveObserver(IObserver observer); void Publish(EventData eventData);}public class Subject: ISubject{ private readonly IList<IObserver> _observers = new List<IObserver>(); public void AddObserver(IObserver observer) { _observers.Add(observer); } public void RemoveObserver(IObserver observer) { _observers.Remove(observer); } public void Publish(EventData eventData) { foreach (var observer in _observers) { observer.Update(eventData); } }}逻辑并没有任何改变,仅仅是实现了一个接口而已,这一步不做其实也没有关系。接下来该做什么应该也很分明了,没错,就是组合到被观察者中去,也就是Dog和Son,上面是具体的实现: public class Dog{ private readonly ISubject _subject; public Dog(ISubject subject) { this._subject = subject; } public void Bark() { Console.WriteLine("遥闻深巷中犬吠"); _subject.Publish(new EventData { Source = this, EventType = "DogBark" }); }}public class Son : IObserver{ private readonly ISubject _subject; public Son(ISubject subject) { this._subject = subject; } public void Update(EventData eventData) { if (eventData.EventType == "DogBark") { Wakeup(); } } public void Wakeup() { Console.WriteLine("既而儿醒,大啼"); _subject.Publish(new EventData { Source = this, EventType = "SonCry" }); }}批改的仅仅是被观察者,观察者不须要做任何扭转。看到下面的调用,不晓得大家有没有一种相熟的感觉呢?没错,这里的应用形式像极了微服务中罕用的事件总线EventBus,事实上,事件总线就是这么实现的,基本原理仅仅是观察者模式继承转组合而已。 ...

May 16, 2021 · 2 min · jiezi

关于设计模式:18-设计模式观察者模式上

观察者模式能够说是十分贴近咱们生存的一个设计模式,为什么这么说呢?哲学上有这么一种说法,叫做“万事万物皆有分割”,原意是说世上没有孤立存在的事物,但其实也能够了解为任何一个事件的产生必然由某个前置事件引起,也必然会导致另一个后置事件。咱们的生存中,充斥着各种各样的互相分割的事件,而观察者模式,次要就是用于解决这种事件的一套解决方案。 示例观察者模式在不同需要下,实现形式也不尽相同,咱们还是举一个例子,而后通过逐渐的改良来粗浅感受一下它是如何工作的。 在中学阶段有一篇课文《口技》,其中有一句“遥闻深巷中犬吠,便有妇人惊觉欠伸,其夫梦话。既而儿醒,大啼。”应该不必翻译吧?咱们接下来就是要通过程序模仿一下这个场景。 先看看他们之间的关系,如下图所示: 初版实现一声狗叫引发了一系列的事件,需要很清晰,也很简略。于是,咱们能够很容易的失去如下实现: public class Wife{ public void Wakeup() { Console.WriteLine("便有妇人惊觉欠伸"); }}public class Husband{ public void DreamTalk() { Console.WriteLine("其夫梦话"); }}public class Son{ public void Wakeup() { Console.WriteLine("既而儿醒,大啼"); }}public class Dog{ private readonly Wife _wife = new Wife(); private readonly Husband _husband = new Husband(); private readonly Son _son = new Son(); public void Bark() { Console.WriteLine("遥闻深巷中犬吠"); _wife.Wakeup(); _husband.DreamTalk(); _son.Wakeup(); }}性能实现了,调用很简略,就不上代码了,从Dog类中能够看出,的确是狗叫触发了后续的一系列事件。然而,有肯定教训的人肯定很快就会发现,这里至多违反了开闭准则和迪米特准则,最终会导致扩大保护起来比拟麻烦。因而,须要改良,而改良的办法也不难想到,无非就是形象出一个基类或接口,让面向实现编程的局部变成面向形象编程,而真正要害的是形象什么的问题。难道是形象一个基类,而后让Wife,Husband,Son继承自该基类吗?他们都是家庭成员,看似如同可行,但它们并没有公共的实现,而且如果后续再退出猫,老鼠或者其它什么的呢?就会变得更加驴唇不对马嘴。面对这种未知的变动,显然很难形象出一个公共的基类,而针对“察看事件产生”这个行为形象出接口或者更适合。 演进一-繁难观察者模式依据这个思路,上面看看改良后的实现,先定义一个公共的接口: public interface IObserver{ void Update();}这里定义了一个跟任何子类都无关的void Update()办法,这也是没方法的方法,因为咱们不可能间接对Wakeup()或者DreamTalk()办法进行形象,只能通过这种形式标准一个公共的行为接口,意思是当被察看的事件产生时,更新具体实例的某些状态。而具体实现类就简略了: ...

May 15, 2021 · 3 min · jiezi

关于设计模式:初学-Java-设计模式十七实战中介者模式-菜鸟驿站

一、中介者模式介绍1. 解决的问题次要解决当对象与对象之间存在大量关联关系时,若一个对象产生扭转,要跟踪与之相干的对象,同时做出相应解决的问题。 2. 定义中介者模式是一种行为设计模式,能缩小对象之间凌乱无序的依赖关系。该模式会限度对象之间的间接交互,迫使它们通过一个中介者对象进行单干。 3. 利用场景当一些对象与其余对象严密耦合以至于难以对其进行批改时,可应用中介者模式。当组件因过于依赖其余组件而无奈在不同利用中复用时,可应用中介者模式。为了在不同情景下复用一些根本行为,导致须要被迫创立大量组件子类时,可应用终结者模式。二、中介者模式优缺点1. 长处繁多职责准则:能够将多个组件间的交换抽取到同一地位,使其更易于了解和保护。开闭准则:无需批改理论组件就能减少新的中介者。能够加重利用中多个组件的耦合状况。能够更不便地复用各个组件。2. 毛病一段时间后,中介者可能会演变为上帝对象。三、中介者模式利用实例:菜鸟驿站1. 实例场景置信大家平时快递来不及拿的话,大部分时候都会抉择让快递小哥将快递放到菜鸟驿站,咱们在放学/上班后再去菜鸟驿站拿本人的快递。同时,咱们如果有快递须要寄出,也是当初菜鸟驿站填写寄件单,而后快递小哥从菜鸟驿站拿到快递,发货。 其实在这里,菜鸟驿站就是一个中介者,承当着快递小哥和咱们之间的重要交换枢纽。 明天,咱们就以菜鸟驿站为例,介绍一下中介者模式。 2. 中介者模式实现2.1 工程构造mediator-pattern└─ src ├─ main │ └─ java │ └─ org.design.pattern.mediator │ ├─ model │ │ ├─ ExpressPackage.java │ │ ├─ Courier.java │ │ └─ User.java │ └─ service │ ├─ CourierStation.java │ └─ impl │ └─ CaiNiaoCourierStation.java └─ test └─ java └─ org.design.pattern.mediator └─ CourierStationTest.java2.2 代码实现2.2.1 实体类快递包裹 /** * 快递包裹 */@Getter@Setter@AllArgsConstructorpublic class ExpressPackage { /** * 包裹id */ private String id; /** * 包裹名称 */ private String name; /** * 收件人电话 */ private String consigneePhoneNumber; /** * 发件快递站 */ private CourierStation sendCourierStation; /** * 收件快递站 */ private CourierStation receiveCourierStation;}快递员 ...

May 15, 2021 · 3 min · jiezi

关于设计模式:你有原则么懂原则么想了解么快看设计模式原则篇让你做个有原则的程序员

前言无论做啥,要想好设计,就得多扩大,少批改 设计准则一句话演绎目标开闭准则对扩大凋谢,对批改敞开升高保护带来的新危险依赖倒置准则高层不应该依赖低层,要面向接口编程更利于代码构造的降级扩大繁多职责准则一个类只干一件事,实现类要繁多便于了解,进步代码的可读性接口隔离准则一个接口只干一件事,接口要精简繁多性能解耦,高聚合、低耦合迪米特法令不该晓得的不要晓得,一个类应该放弃对其它对象起码的理解,升高耦合度只和敌人交换,不和陌生人谈话,缩小代码臃肿里氏替换准则不要毁坏继承体系,子类重写办法性能产生扭转,不应该影响父类办法的含意避免继承泛滥合成复用准则尽量应用组合或者聚合关系实现代码复用,少应用继承升高代码耦合开闭准则此准则是由"Bertrand Meyer"提出的。原文是:"Software entities should be open for extension,but closed for modification"。就是说模块应答扩大凋谢,而对批改敞开。模块应尽量在不批改原(是"原",指原来的代码)代码的状况下进行扩大 开闭准则的含意当利用的需要扭转时,在不批改软件实体的源代码或者二进制代码的前提下,能够扩大模块的性能,使其满足新的需要。 开闭准则的作用对软件测试的影响软件恪守开闭准则的话,软件测试时只须要对扩大的代码进行测试就能够了,因为原有的测试代码依然可能失常运行。能够进步代码的可复用性粒度越小,被复用的可能性就越大;在面向对象的程序设计中,依据原子和形象编程能够进步代码的可复用性。能够进步软件的可维护性恪守开闭准则的软件,其稳定性高和延续性强,从而易于扩大和保护。里氏替换准则里氏替换准则次要论述了无关继承的一些准则,也就是什么时候应该应用继承,什么时候不应该应用继承,以及其中蕴含的原理。里氏替换原是继承复用的根底,它反映了基类与子类之间的关系,是对开闭准则的补充,是对实现抽象化的具体步骤的标准。 里氏替换准则的作用它克服了继承中重写父类造成的可复用性变差的毛病。它是动作正确性的保障。即类的扩大不会给已有的零碎引入新的谬误,升高了代码出错的可能性。增强程序的健壮性,同时变更时能够做到十分好的兼容性,进步程序的维护性、可扩展性,升高需要变更时引入的危险。 里氏替换准则的实现办法里氏替换准则艰深来讲就是:子类能够扩大父类的性能,但不能扭转父类原有的性能。也就是说:子类继承父类时,除增加新的办法实现新增性能外,尽量不要重写父类的办法。 依赖倒置准则要面向接口编程,不要面向实现编程。 依赖倒置准则是实现开闭准则的重要途径之一,它升高了客户与实现模块之间的耦合。 因为在软件设计中,细节具备多变性,而形象层则绝对稳固,因而以形象为根底搭建起来的架构要比以细节为根底搭建起来的架构要稳固得多。这里的形象指的是接口或者抽象类,而细节是指具体的实现类。 应用接口或者抽象类的目标是制订好标准和契约,而不去波及任何具体的操作,把展示细节的工作交给它们的实现类去实现。 依赖、倒置准则的作用依赖倒置准则的次要作用如下。依赖倒置准则能够升高类间的耦合性。依赖倒置准则能够进步零碎的稳定性。依赖倒置准则能够缩小并行开发引起的危险。依赖倒置准则能够进步代码的可读性和可维护性。繁多职责准则繁多职责准则规定一个类应该有且仅有一个引起它变动的起因,否则类应该被拆分 繁多职责准则的长处繁多职责准则的外围就是管制类的粒度大小、将对象解耦、进步其内聚性。如果遵循繁多职责准则将有以下长处。 升高类的复杂度。一个类只负责一项职责,其逻辑必定要比负责多项职责简略得多。进步类的可读性。复杂性升高,天然其可读性会进步。进步零碎的可维护性。可读性进步,那天然更容易保护了。变更引起的危险升高。变更是必然的,如果繁多职责准则恪守得好,当批改一个性能时,能够显著升高对其余性能的影响。接口隔离准则尽量将臃肿宏大的接口拆分成更小的和更具体的接口,让接口中只蕴含客户感兴趣的办法。一个类对另一个类的依赖应该建设在最小的接口上 要为各个类建设它们须要的专用接口,而不要试图去建设一个很宏大的接口供所有依赖它的类去调用。 接口隔离准则和繁多职责都是为了进步类的内聚性、升高它们之间的耦合性,体现了封装的思维,但两者是不同的: 繁多职责准则重视的是职责,而接口隔离准则重视的是对接口依赖的隔离。繁多职责准则次要是束缚类,它针对的是程序中的实现和细节;接口隔离准则次要束缚接口,次要针对形象和程序整体框架的构建。 接口隔离准则的长处接口隔离准则是为了束缚接口、升高类对接口的依赖性,遵循接口隔离准则有以下 5 个长处。 将臃肿宏大的接口合成为多个粒度小的接口,能够预防外来变更的扩散,进步零碎的灵活性和可维护性。接口隔离进步了零碎的内聚性,缩小了对外交互,升高了零碎的耦合性。如果接口的粒度大小定义正当,可能保证系统的稳定性;然而,如果定义过小,则会造成接口数量过多,使设计复杂化;如果定义太大,灵活性升高,无奈提供定制服务,给整体我的项目带来无奈意料的危险。应用多个专门的接口还可能体现对象的档次,因为能够通过接口的继承,实现对总接口的定义。能缩小我的项目工程中的代码冗余。过大的大接口外面通常搁置许多不必的办法,当实现这个接口的时候,被迫设计冗余的代码。迪米特法令如果两个软件实体毋庸间接通信,那么就不该当产生间接的互相调用,能够通过第三方转发该调用。其目标是升高类之间的耦合度,进步模块的绝对独立性。 迪米特法令中的“敌人”是指:以后对象自身、以后对象的成员对象、以后对象所创立的对象、以后对象的办法参数等,这些对象同以后对象存在关联、聚合或组合关系,能够间接拜访这些对象的办法。迪米特法令的长处迪米特法令要求限度软件实体之间通信的宽度和深度,正确应用迪米特法令将有以下两个长处。 升高了类之间的耦合度,进步了模块的绝对独立性。因为亲合度升高,从而进步了类的可复用率和零碎的扩展性。然而,适度应用迪米特法令会使零碎产生大量的中介类,从而减少零碎的复杂性,使模块之间的通信效率升高。所以,在釆用迪米特法令时须要重复衡量,确保高内聚和低耦合的同时,保证系统的构造清晰。 合成复用准则要尽量先应用组合或者聚合等关联关系来实现,其次才思考应用继承关系来实现。 如果要应用继承关系,则必须严格遵循里氏替换准则。合成复用准则同里氏替换准则相辅相成的,两者都是开闭准则的具体实现标准。 合成复用准则的重要性通常类的复用分为继承复用和合成复用两种,继承复用尽管有简略和易实现的长处,但它也存在以下毛病。 继承复用毁坏了类的封装性。因为继承会将父类的实现细节裸露给子类,父类对子类是通明的,所以这种复用又称为“白箱”复用。子类与父类的耦合度高。父类的实现的任何扭转都会导致子类的实现发生变化,这不利于类的扩大与保护。它限度了复用的灵活性。从父类继承而来的实现是动态的,在编译时曾经定义,所以在运行时不可能发生变化。采纳组合或聚合复用时,能够将已有对象纳入新对象中,使之成为新对象的一部分,新对象能够调用已有对象的性能,它有以下长处。 它维持了类的封装性。因为成分对象的外部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。新旧类之间的耦合度低。这种复用所需的依赖较少,新对象存取成分对象的惟一办法是通过成分对象的接口。复用的灵活性高。这种复用能够在运行时动静进行,新对象能够动静地援用与成分对象类型雷同的对象。下一章节咱们对设计模式进行具体解说,并解读jdk源码

May 14, 2021 · 1 min · jiezi

关于设计模式:你还在为面试设计模式烦恼么java设计模式看这一专栏就够了开篇

前言设计模式无论是在开发中还是在面试中都占有肯定位置。一般来说中小型的互联网公司并不在意设计模式,稍大一些的公司面试就会讲究面试人员的设计模式的了解与应用,以及设计模式在源码中的解读。我此篇专栏就是帮忙各位读者来攻破设计模式的应用技巧,与源码解读。晋升本身硬实力。 概念软件设计模式(Design pattern),又称设计模式,是一套被重复应用、少数人通晓的、通过分类编目标、代码设计教训的总结。应用设计模式是为了可重用代码、让代码更容易被别人了解、保障代码可靠性、程序的重用性。其目标很简略,让你的代码可复用,可读性强,稳定性好 学习设计模式能给你带来什么面向对象的了解(封装性、继承性和多态性)帮忙开发人员晋升编程的能力,进步对代码的设计能力你的程序更加标准化、开发效率大大提高,从而缩短软件的开发周期。使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。设计模式的分类创立型模式结构型模式行为型模式单例,原型,形象工厂,建造者 ,工厂办法代理,适配器,桥接,装璜,外观,享元,组合策略,命令,职责链,状态,观察者,中介者,迭代器,访问者,备忘录,模板办法,解释器创立型模式:用于形容“怎么创建对象”,它的次要特点是“将对象的创立与应用拆散”结构型模式:用于形容如何将类或对象按某种布局组成更大的构造行为型模式:用于形容类或对象之间怎么相互协作共同完成单个对象都无奈独自实现的工作,以及怎么调配职责 开篇就到这里,下一节介绍设计模式的准则

May 14, 2021 · 1 min · jiezi

关于设计模式:初学-Java-设计模式十六实战迭代器模式-你有多少-QQ-好友呢

一、迭代器模式介绍1. 解决的问题次要解决遍历整个汇合对象的问题。 2. 定义迭代器模式是一种行为设计模式,能在不裸露底层表现形式(列表、栈和树等)的状况下遍历汇合中所有的元素。 3. 利用场景当汇合背地为简单的数据结构,且心愿对客户端暗藏其复杂性时(处于应用便利性或安全性思考),能够应用迭代器模式。缩小程序中反复的遍历代码,能够应用迭代器模式。心愿代码可能遍历不同的甚至无奈预知的数据结构,能够应用迭代器模式。二、迭代器模式优缺点1. 长处繁多职责准则:通过将体积宏大的遍历算法代码抽取为独立的类,能够对客户端代码和汇合进行整顿。开闭准则:可实现新型的汇合和迭代器并将其传递给现有代码,无需批改现有代码。能够并行遍历同一汇合,因为每个迭代器对象都蕴含其本身的遍历状态;同时,也能够暂停遍历并在须要时持续。2. 毛病如果程序只与简略的汇合进行交互,应用迭代器模式可能会矫枉过正。对于某些非凡汇合,应用迭代器可能比间接遍历的效率低。三、迭代器模式利用实例: 你有多少 QQ 好友呢?1. 实例场景微信的崛起,就是QQ的落寞,当初用QQ的应该越来越少了,但QQ很多性能还是挺好用的,比方好友的分组性能,这样就齐全能够将从学校、网络上、工作等意识的好友离开,那么离开当前,怎么晓得到底有多少 QQ 好友呢? 明天,以遍历各个分组的好友为例,介绍一下迭代器模式。 2. 迭代器模式实现2.1 工程构造iterator-pattern└─ src ├─ main │ └─ java │ └─ org.design.pattern.iterator │ ├─ model │ │ ├─ Friend.java │ │ └─ Group.java │ └─ tool │ ├─ Iterator.java │ ├─ Collection.java │ └─ impl │ ├─ IteratorImpl.java │ └─ CollectionImpl.java └─ test └─ java └─ org.design.pattern.iterator └─ IteratorTest.java2.2 代码实现2.2.1 实体类QQ 好友 /** * QQ 好友 */@Getter@Setter@AllArgsConstructorpublic class Friend { /** * 用户id */ private String id; /** * 昵称 */ private String nickname; /** * 备注 */ private String noteName;}QQ 分组 ...

May 10, 2021 · 4 min · jiezi

关于设计模式:17-设计模式状态模式

说到状态模式,顾名思义,应该就是跟状态相干的设计模式了,不过,咱们还是跟后面一样,先不论状态模式是个什么货色,先从一个小小的例子登程,看看状态模式能为咱们解决什么问题。 示例当初须要实现一个交通灯调度程序,交通灯的色彩须要在红灯->绿灯->黄灯->红灯之间循环转换,然而不容许绿灯->红灯或黄灯->绿灯等状况。这属于交通规则的常识,当初咱们用程序实现它,先看看咱们最传统的思考和实现形式。 首先,咱们会很容易想到须要定义一个交通灯色彩的枚举: public enum LightColor{ Green, Red, Yellow}而后,定义一个交通灯的类,在交通灯类中解决色彩转换及相应的业务逻辑,代码如下: public class TrafficLight{ private LightColor _lightColor; public TrafficLight() { _lightColor = LightColor.Red; } public void Turn() { if (_lightColor == LightColor.Red) { Console.WriteLine("红灯停"); _lightColor = LightColor.Green; } else if (_lightColor == LightColor.Green) { Console.WriteLine("绿灯行"); _lightColor = LightColor.Yellow; } else if (_lightColor == LightColor.Yellow) { Console.WriteLine("黄灯亮了等一等"); _lightColor = LightColor.Red; } }}最初,再无妨调用运行一下: static void Main(string[] args){ TrafficLight light = new TrafficLight(); light.Turn(); light.Turn(); light.Turn(); light.Turn();}不言而喻,这段代码是齐全满足需要的,并且逻辑谨严,调用形式也极其简略,如果需要不变,这或者就是最好的实现形式了。然而通过后面设计准则的陶冶,咱们晓得,需要不变是不可能的。因而,咱们很容易就会发现这段代码存在的问题,充斥着if-else的条件分支,这就意味着扩大艰难。这里例子简略,可能并不显著,然而实在我的项目中必然会有更多的条件分支和更多相似Turn()的办法,这会导致整个我的项目扩大保护起来极其艰难,因为,它重大违反了开闭准则。 ...

May 1, 2021 · 2 min · jiezi

关于设计模式:洞察设计模式的底层逻辑

简介: 设计模式是开发同学常常聊到的话题,也常常被用到理论的开发我的项目中,纯熟的人能够做到信手拈来,不相熟的人陷入苦思冥想中。笔者认为,不仅仅要把握设计模式的用法,更要洞察设计模式的底层逻辑,只有那样,能力做到遇到理论的问题能够应用适合的设计模式去解决。 作者 | 不拔起源 | 阿里技术公众号 设计模式是开发同学常常聊到的话题,也常常被用到理论的开发我的项目中,纯熟的人能够做到信手拈来,不相熟的人陷入苦思冥想中。笔者认为,不仅仅要把握设计模式的用法,更要洞察设计模式的底层逻辑,只有那样,能力做到遇到理论的问题能够应用适合的设计模式去解决。 一 你应该关注底层逻辑1 设计模式的段子段子一:你让他给你讲设计模式,他给你讲故事,听完后,又蹦又跳,乐坏了;看原著设计模式和理论写代码时,又是又蹦又跳,那是疯了。 段子二:你让他给你讲设计模式,他给你讲架构;你和他讲架构,他和你讲建筑学;你和他讲建筑学,他和你讲哲学…… 下面两个典型的段子,能够看到大家平时学习设计模式的无奈,故事听懂了,但仍然没有把握设计模式,甚至设计模式的类图大家也画得出,却还是不能灵便把握设计模式。究其基本的起因是没有把握设计模式的内核思维,只是晓得设计模式的外在模式,相当于只学到了“招式”,没有学到“内功”。 2 底层逻辑的实质很多事物都有底层逻辑,当把握了事物的底层逻辑之后,很多事就好办了,如果你曾经洞察到了最外围的法则,在理论工作中就只须要依照法则去执行就能够。例如,咱们看到很多营销文案让人眼前一亮、叹为观止,如果要让咱们去写这些营销文案,一开始还找不到门道,写进去的题目平平淡淡,不够吸引人。那营销文案背地的底层逻辑是什么呢?咱们看到很多文案如“激发学习潜能的四大策略”、“如何在10天内记忆5000+单词”、“一文提醒为什么你比他人差”……这些文案有的应用陈说手法,有的应用疑难手法,有的应用比照手法,有的应用感叹手法……再往下开掘,不论应用哪种手法,实质来讲是命中了人的爽点或痛点,再用这个底层逻辑去看各种文案,有的命中你的痛点,比方你想记忆更多的单词,事实记不住单词;比方你想胜利,但致力了很久还没有成果……有的命中你的爽点:你花更少的钱就能取得更好的服务;你不必出门就能赚到钱……当你洞察到了营销文案背地的底层逻辑,你当初也能够写出吸引眼球的文案,这就是底层逻辑的力量! 咱们学习23种设计模式,它们被划分成创立型设计模式、结构型设计模式、行为型设计模式,这就像营销文案的写作手法一样,那么设计模式的底层逻辑到底是什么呢? 二 设计模式的底层逻辑1 设计模式的基石平时咱们在写代码的时候,常常见到如下三种类型的代码:面条型的代码、过程式的代码和面向对象的代码,这里以一个例子来阐明这三种类型的编码特点。 面条型代码就是所有逻辑堆砌在一起,就像写一篇文章,不怎么分段落。比方现代雕刻文字,在一块木板上雕刻一首诗,如果诗人要把其中的一个批改下,那得从新雕刻这首诗。非常容易发现这种模式的毛病:耦合太重大,牵一发而动全身。过程式代码在面条型代码根底上有了很大的提高,它遵循“自顶向下,逐步求精”的思维,把一个大问题划分成若干个小问题,分而治之。对应下面雕刻诗的例子,诗是由若干个行组成的,如果每块木板上只雕刻一行诗,万一要改某个字,只用从新雕刻那一行就行,不必从新雕刻整首诗。但如果要批改多个字,而且在不同的行时,这种极其状况下整个首诗又得从新雕刻了。面向对象代码换了一种思考形式,诗是由行组成的,行又是由一个个字组成的,这也即是活字印刷的思维,这些字还能够复用于其它不同的诗,复用性十分强。从下面的例子能够看到,外围还是洞察到事物的构造和关系,首先答复的是what,而不是how。过程式就是过分强调了how,一开始就思考怎么去做,过程式思维是以本人为核心,导演了整个性能流程,本人承当了太多本人不应该承当的职责,整个设计就显得不灵便。面向对象是从对象的角度去看问题,解决问题是由各个对象合作实现,设计模式的基石就是面向对象,脱离了面向对象去谈设计模式那是耍流氓。 2 设计模式的鼻祖设计模式有一本经典的书籍:《设计模式:可复用面向对象软件的根底》,在书中作者提到了一句话:“找到变动,封装变动”,这才是设计模式的底层逻辑。很多人漠视了这句话,反而去追寻各种模式的招式,遇到理论的问题又找不到适合的设计模式去解决了。“找到变动,封装变动”十分简练地提醒了设计模式的实质,细细品味这句话,再去看23种设计模式,每种设计模式都在应答变动的事,比方策略模式,具体的策略在变动;工厂模式,创立的对象在变动;模板模式,具体模板算法实现在变动……这就好比营销文案的底层逻辑:命中了你的痛点或爽点,具体痛点和爽点是什么须要去寻找。在理论问题中,须要咱们去看什么在变动,抉择哪种设计模式比拟适合。 3 再谈底层逻辑再回过头看底层逻辑,平时咱们看到的景象只是景象层,外围是要洞察到事物的底层逻辑,只有那样能力真正了解景象、使用法则,如果你不懂营销文案背地的底层逻辑,你所有的怠惰都是低水平的反复,很难写出高质量的营销文案,偶然一两次起得了良好的成果你也不晓得为什么能吸引人。设计模式也是一样,你能相熟地画出各种模式的UML图,可你仍然还是用不好设计模式,实质还是没有把握设计模式的底层逻辑,只看到了设计模式的景象层的招式。设计模式的底层逻辑是“找到变动,封装变动”,这里就有两个问题:什么在变动,如何封装变动,巨匠认为咱们都晓得,所以并没有讲具体怎么去寻找变动,怎么去封装变动。接下来具体谈谈怎么去使用设计模式的底层逻辑。 三 设计模式要答复的两个问题1 什么在变动“找到变动,封装变动”这句话,首先要答复的是什么在变动,如果变动没有找到,就不可能封装变动。笔者这里以对象生命周期的视角去对待对象的变动,对象是由创立而产生,而后被应用,最初是沦亡。对象有三个不同维度的变动:对象构造的变动、对象规格的变动、对象行为的变动。以对象构造变动为例,对象的关系划分成两类:线性关系和非线性关系(树和图),在线性关系中,如何解决一个对象的变动不会影响到关联的对象?在树型构造中,如何解决一直新减少对象的问题?在图型构造中,如何解决用户方便使用简单零碎的问题? 找到变动是最为要害,不同的业务问题,遇到的变动问题也是不一样的,外围是要找到这些变动。比方对象规格的变动,有数量的变动、类型的变动、外观的变动,在理论编码的过程中就要有这种思考,比方创立一个对象,再深刻思维下,有没有其它类型的对象?数量有没有变动?……只有找到了这些变动,具体怎么去封装变动就是技术的问题,接下来探讨如何封装变动。 2 如何封装变动从封装的类型上看,有数据的封装、办法的封装、类型的封装等。就具体的封装办法而言,常见的有配置项、接口、形象办法、类、注解、插件等具体的伎俩,再往上看次要应用了继承、组合的办法,再往上看封装的准则,常见的准则有繁多职责、开闭准则、依赖倒置、隔离准则……大部分人平时更多地关注如何封装变动,并没有深刻去思考什么在变动。 四 用底层逻辑推导结构型设计模式1 寻找对象构造的变动从UML看,对象之间的关系有依赖、泛化、组合、聚合,但就构造关系上看只有两种,线性关系和非线性关系。线性关系比较简单,就是一对一的关联关系,非线性关系分成两种:树型关系和图型关系。 关系构造有变动,意味着依赖产生了变动,比方线性关系中的变动,A依赖的B产生了变动,此时B变动了就会影响A,怎么做到B的变动不影响A就是要思考的问题。 2 应答线性变动如下面所讲,如果B产生了变动,因为A依赖B,则对象A也要改变动,如何缩小对A的影响呢?这里有两种办法:一种是通过减少适配来解决,另一种是通过代理来解决。这两种办法的要点都是一个对象不与变动的对象间接关联,不论是适配还是代理,都是引入了第三方来与B关联,第三方负责与B进行交互,B对A是没有感知的。有的人马上发现了一个问题,这不是把问题转移到第三方上了吗?乍一看,还真是这么回事,如果咱们再发散思考,如果除了A要与B关系,还有E、F……,如果B一改就关联的所有对象就要变动,这种代价就比拟高,如果只与第三方关系,只用改一个中央,老本要少得多。 3 应答非线性变动非线性关系比线性关系要简单,常见也有两种办法:一种是通过注册机制,另一种通过形象层屏蔽复杂性。当一个对象蕴含多个对象时,如果间接去治理,须要承当的职责太多,通过注册机制就比拟好解决,减少一个对象,是通过注册机制被动告知对象。另外一种办法就是通过形象层屏蔽复杂性,比方门面模式,在门面内把所有的复杂度都躲避,对外提供简洁的接口。 五 业务变动之道设计模式还是要利用到理论的业务中能力施展它的价值, Alan Shalloway 提到一个观点:无奈预测哪里有变动,但能晓得哪里可能有变动。平时咱们在做业务需要开发时,要有这种辨认变动的意识,先不要陷入面向过程的思维中,不要一上来就思考如何去实现,而是思考它是什么,会有哪些变动,比方对象的数量、对象的外观、对象的品种……当把这些思考分明之后,能力设计得更正当。 比方笔者之前做清结算业务时,投资人理财到期后,会将本息金额的钱打给投资人,刚开始只有大华领取通道,这里就要想到一个问题,大华领取只是一种具体的实现形式,还会有没有其它的领取形式,如果有就要做形象设计,设计一个通用的领取模板类,每接一种新的领取通道时,只用重写模板类中的几个办法即可,后续又接了民生银行领取、连连领取。 六 对象设计之道有了后面所讲内容的铺垫,这里再深刻总结下对象设计的一些思考。对象设计有三个问题:有哪些对象?对象之间的关系是怎么的?对象的职责有哪些?当把这三个问题梳理分明了,对象设计也就容易得多,也是面向对象分析与设计的外围。失常来讲,咱们晓得构造决定性能,性能决定行为,这是十分合乎人的逻辑意识,但要想理解分明对象的构造又是十分难的,就像新冠病毒的分子结构也不是那么容易破解的,尤其是简单业务,它所蕴含的业务对象并不那么容易弄清楚它的构造。 咱们能够反过来思考,当有一种业务场景时,先思考它的职责是什么,再去思考应该由哪些业务对象去承当,这也是典型的演绎思维。比方在优惠券业务中,它的业务流动就三个:建券、发券、用券,也就是任何一个优惠券零碎,它要提供这三个最为根底的能力,这三个能力又对应到两个业务对象:券批次和券实例,券批次相当于是券的模板,告知优惠券的估算有多少、券面额是多少、应用条件是什么……,具体发放到用户手上的才是券实例。 当有了业务对象之后,就要通过用例去思考对象模型的所蕴含的属性和办法有哪些,这个过程并不是一次就能完满实现的,而是通过屡次打磨才行,这外面就要遵循一些准则,比方繁多职责、开闭准则、依赖倒置的准则……,让整个模型的可扩展性更好。 七 一个案例最初拿一个案例来讲,店铺类目是卖家为了不便买家有针对性地选购商品而对商品做出的归类,比方上新类目,把最近30天上架的商品归类在一起,不便买家查找。遇到的挑战就是怎么用一套业务模型去反对不同业务方高度定制化的需要,有的需求方要求有三级类目,有的业务方要求浮动的两级类目,同时圈品形式也不一样,有的业务方要求有主动圈选商品,圈选商品的条件还不一样,如按价格圈选、按商品上架工夫圈选、按评估圈选…… 怎么去设计这套模型呢,还是从店铺类目标定义去看,店铺类目至多蕴含两个要害的因素:类目构造和类目圈品,因为归类产生了构造,商品产生了圈品,思考到类目有不同的层级和圈品条件,所以第一版模型就很快设计进去了,从模型中能够看到能撑持业务的诉求,尤其是圈品条件中业务方能够自定义各种条件注册到平台上,看到这个设计,笔者心田还是快慰的。 但在实现的过程中,发现了一些问题,如根类目和子类目,在业务模型中有这两个概念,在代码上也要有这两个概念,正是引入了这两个概念,代码写起来就比拟麻烦,自身它们并没有什么区别,当初人为地把它们辨别开来,很多逻辑都要写两遍。笔者又进模型进行了优化,变成了第二版模型,这个模型就更简略了。 这里想谈的两点是要保障模型的简洁性和升高技术复杂度,技术人喜爱钻研技术,喜爱把一些学到的技术利用到我的项目中,这实际上是一种技术偏见,认为这样能力体现出技术复杂度和技术能力。简单并不见得有技术含量,就像设计模式的底层法则,作者并没有长篇大谈,而是只有8个字"找到变动,封装变动",大道至简就是这个情理,咱们学习设计模式,不要为了用设计模式而用,肯定要思考为什么用,解决了什么问题,这样才有价值。 原文链接本文为阿里云原创内容,未经容许不得转载。

April 20, 2021 · 1 min · jiezi

关于设计模式:HeadFirst设计模式读书笔记二观察者模式

作者:折纸集体博客:https://www.zhezhi.press记录菜鸡的成长之旅!1. 模式定义和特点 观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态产生扭转时,所有依赖于它的对象都失去告诉并被自动更新。这种模式有时又称作公布-订阅模式、模型-视图模式,它是对象行为型模式。 观察者模式是一种对象行为型模式,其次要长处如下。 升高了指标与观察者之间的耦合关系,两者之间是形象耦合关系。合乎依赖倒置准则。指标与观察者之间建设了一套触发机制。它的次要毛病如下。 指标与观察者之间的依赖关系并没有齐全解除,而且有可能呈现循环援用。当观察者对象很多时,告诉的发布会破费很多工夫,影响程序的效率。2. 模式的类图构造 观察者须要获取到某些数据,但只有主题对象才是真正治理这些数据的角色;这比起所有观察者对立管制同一份数据具备更低的耦合性 咱们常说的高内聚,低耦合是什么意思?我的了解:该紧密联系的时候就紧密联系,不该紧密联系的时候就该拆分进去。(同一模块内性能没有必要拆分)松耦合当两个对象松耦合时它们仍然能够交互,但不理解彼此的细节(对象之间的相互依赖降到了最低) --> 实现了有弹性的零碎 对于观察者的所有,主题只晓得观察者实现了某个接口(也就是Observer接口)。主题不须要晓得观察者的具体类是谁、做了些什么或其余任何细节。 任何时候咱们都能够减少新的观察者。因为主题惟一依赖的货色是一个实现Observer接口的对象列表,所以咱们能够随时减少观察者。事实上,在运行时咱们能够用新的观察者取代现有的观察者,主题不会受到任何影响。同样的,也能够在任何时候删除某些观察者。 有新类型的观察者呈现时,主题的代码不须要批改。咱们能够独立地复用主题或观察者。如果咱们在其余中央须要应用主题或观察者,能够轻易地复用。因为二者并非紧耦合。 扭转主题或观察者其中一方,并不会影响另一方。因为两者是松耦合的,所以只有他们之间的接口仍被恪守,咱们就能够自在地扭转他们。 设计准则:为了交互对象之间的松耦合设计而致力3. 模式的实现3.1 Java内置观察者模式类图 3.1.1 如何把对象变成观察者…如同以前一样,实现观察者接口(java.uitl.Observer),而后调用任何Observable对象的addObserver)办法。不想再当观察者时,调用deleteObserver()办法就能够了。 3.1.2 可观察者/主题要如何送出告诉……首先,你须要利用扩大java.util.Observable接口产生“可观察者”类,而后,需个步骤:①先调用setChanged()办法,标记状态曾经扭转的事实。②而后调用两种notifyObservers0办法中的一个:notifyobservers()或 notifyobservers(object arg) 3.1.3 观察者如何接管告诉……同以前一样,观察者实现了更新的办法,然而办法的签名不太一样:如果你想“推”(push)数据给观察者,你能够把数据当作数据对象传送给notifyObservers(arg)办法。否则,观察者就必须从可观察者对象中“拉”(pull)数据。 其中 setChanged()办法是用来标记状态是否扭转的,好让notifyObservers()晓得当它被调用时应该更新观察者。如果调用notifyObservers)之前没有先调用setChanged(),观察者就“不会”被告诉。让咱们看看Observable外部,以理解这所有: 3.2 自定义实现3.2.1 java.util.Observable的弊病java.uitl.Observable实现了它的notifyObservers()办法,这导致了告诉观察者的秩序不同于咱们先前的秩序。谁也没有错,只是单方抉择不同的形式实现罢了。然而能够确定的是,如果咱们的代码依赖这样的秩序,就是错的。为什么呢?因为一旦观察者/可观察者的实现有所扭转,告诉秩序就会扭转,很可能就会产生谬误的后果。这相对不是咱们所认为的松耦合。 首先,因为Observable是一个“类”,你必须设计一个类继承它。如果某类想同时具备Observable类和另一个超类的行为,就会陷入两难,毕竟Java不反对多重继承。这限度了Observable的复用后劲(而减少复用后劲不正是咱们应用模式最原始的动机吗?)。 再者,因为没有Observable接口,所以你无奈建设本人的实现,和Java内置的Observer API搭配应用,也无奈将java.util的实现换成另一套做法的实现(比方说,Observable将要害的办法爱护起来如果你看看ObservableAP1,你会发现setChanged)办法被爱护起来了(被定义成protected)。那又怎么样呢?这意味着:除非你继承自Observable,否则你无奈创立Observable实例并组合到你本人的对象中来。这个设计违反了第二个设计准则:“多用组合,少用继承”。 如果你可能扩大java.util.Observable,那么Observable“可能”能够合乎你的需要。否则,你可能须要像本章结尾的做法那样本人实现这一整套观察者模式。 4. 模式的利用场景在软件系统中,当零碎一方行为依赖另一方行为的变动时,可应用观察者模式松耦合联动单方,使得一方的变动能够告诉到感兴趣的另一方对象,从而让另一方对象对此做出响应。 通过后面的剖析与利用实例可知观察者模式适宜以下几种情景。1、对象间存在一对多关系,一个对象的状态产生扭转会影响其余对象。2、当一个形象模型有两个方面,其中一个方面依赖于另一方面时,可将这二者封装在独立的对象中以使它们能够各自独立地扭转和复用。3、实现相似播送机制的性能,不须要晓得具体收听者,只需散发播送,零碎中感兴趣的对象会主动接管该播送。4、多层级嵌套应用,造成一种链式触发机制,使得事件具备跨域(逾越两种观察者类型)告诉。 5. 总结设计准则: 封装变动多用组合 少用继承针对接口编程 而不是针对实现编程为交互对象之间的松耦合而致力

April 19, 2021 · 1 min · jiezi

关于设计模式:HeadFirst设计模式读书笔记一策略模式

作者:折纸集体博客:https://www.zhezhi.press记录菜鸡的成长之旅!1 从一堆鸭子说起家喻户晓《机器学习》(周志华版)被称为西瓜书,我感觉《Head First 设计模式》也能够被称为鸭子书~ 假如有这么一个模仿鸭子游戏SimUDuck,游戏中会呈现各种鸭子,它们一边游泳一边呱呱叫。于是有这么一个鸭子超类,并且让各种鸭子继承这个超类; 这看起来仿佛还不错,所有的鸭子都会继承Duck超类,并且只须要重写display办法以打印本人的特色就能够。但需要是在变动的。 2 让鸭子飞起来!好吧,看起来不难,咱们只须要给Duck类加一个fly()办法并实现就能够了;的确这样一来所有继承Duck类的鸭子都会飞了,然而咱们疏忽了一个事实——不同子类之间的差异性,橡皮鸭子本来不会飞当初飞起来了! 对代码的部分批改 影响的不肯定只停留在部分;当波及“保护”时,为了“复用”目标而应用继承,终局并不完满我的了解:对超类的批改要审慎,防止造成不必要的麻烦!如无必要,勿增实体2.1 解决办法:子类重写咱们能够重写不会飞的橡皮鸭子的fly办法,将其改为什么也不做就能够了。这的确解决了橡皮鸭能够飞的问题,然而当前每次设计新的子类的时候,咱们都须要查看fly、quack、swim等办法,这就失去了复用的意义。 通过继承提供Duck的行为,可能会带来的毛病 代码在多个子类中反复(须要改写行为以适应不同子类)运行时的行为不容易扭转(无奈灵便切换)很难晓得所有鸭子的全副行为扭转会牵一发而动全身,导致其余鸭子不想要的扭转2.2 解决办法:通过接口接口是对行为的形象,能够把fly()、quack()从超类中提取进去,放进Flyable、Quackable接口,而后只有会飞、会叫的鸭子才回去实现这个接口。但这一来反复的代码将变得更多,对于每一种会飞、会叫的鸭子都须要去实现对应的接口,此外还有不同航行办法、不同叫声的叫法,这使得代码的可复用性降得很低。 2.3 从新扫视问题首先咱们晓得在这个案例中,fly是新退出的需要~并且应用继承并不能很好地解决问题,因为鸭子的行为在子类里一直地扭转,并且让所有的子类都有这些行为是不失当的。Flyable与Quackable接口一开始仿佛还挺不错,解决了问题(只有会飞的鸭子才继承Flyable),然而Java接口不具备实现代码,所以继承接口无奈达到代码的复用。这意味着: 无论何时你须要批改某个行为,你必须得往下追踪并在每一个定义此行为的类中批改它,一不小心,可能会造成新的谬误!侥幸的是,有一个设计准则,恰好实用于此情况。 设计准则: 找出利用中可能须要变动之处,把它们独立进去,不要和那些不须要变动的代码混在一起。上面是这个准则的另一种思考形式:“把会变动的局部取出并封装起来,以便当前能够轻易地改变或裁减此局部,而不影响不须要变动的其余局部”。-->零碎变得更有弹性 这样的概念很简略,简直是每个设计模式背地的精力所在。所有的模式都提供了一套办法让“零碎中的某局部扭转不会影响其余局部”。好,该是把鸭子的行为从Duck类中取出的时候了! 3 抽离易于变动的局部一种办法是建设2组齐全远离Duck类的Class,每一组类将实现fly、或者是quack,而类中有对于fly的不同实现;而且能够使得鸭子的行为能够动静地扭转(setter) 设计准则:针对接口编程,而不是针对实现编程。咱们利用接口代表每个行为,行为的每个实现都将实现其中的一个接口。这样的做法迥异于以往,以前的做法是:行为来自Duck超类的具体实现,或是继承某个接口并由子类自行实现而来。 这两种做法都是依赖于“实现”,咱们被实现绑得死死的,没方法更改行为(除非写更多代码)。在咱们的新设计中,鸭子的子类将应用接口(FlyBehavior与QuackBehavior)所示意的行为,所以理论的“实现”不会被绑死在鸭子的子类中(鸭子不会负责实现Flyable、Quackable接口)。(换句话说,特定的具体行为编写在实现了FlyBehavior与QuakcBehavior的类中,从而实现理解耦)。 这样的设计,能够让航行和呱呱叫的动作被其余的对象复用,因为这些行为曾经与鸭子类无关了;并且咱们也能够新增一些行为(不同的实现),不会影响到已有的行为类和“应用”其余已有行为的鸭子类。 这么一来,有了继承的“复用”益处,却没有继承所带来的包袱。 4 复盘你兴许可能听过Has-A is Better than is-A的说法,兴许你可能像我一样此前并没有很间接地感触到或者思考过Why Has-A is Better than is-A?但通过鸭子的例子我想你应该有一些感触了,is-A也就是继承的关系(不同的鸭子继承超类Duck),而has-A更偏差于组合的关系(鸭子类有FlyBehavior类和QuackBehavior类,鸭子是容器/对象,而后两者是容器/对象的组件类) 设计准则:多用组合,少用继承如你所见,应用组合建设零碎具备很大的弹性,不仅可将算法族(对于同一个行为的不同实现办法)封装成类,更能够“在运行时动静地扭转行为”(setter办法),只有组合的行为对象合乎正确的接口标准即可。组合用在许多设计模式中,它也有许多长处和毛病,在之后的学习中咱们还会持续探讨; 5 策略模式策略模式是一种行为型设计模式, 它能够在运行时抉择算法;与间接实现某个算法不同,代码在运行时能够抉择在算法族中选取一个执行。(In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use.wikipedia) ...

April 19, 2021 · 1 min · jiezi

关于aop:js实现AOP面向切面编程

js实现AOP,面向切面编程面向切面编程(AOP)是java罕用编程思维,它的作用是在某个函数上进行切割,能够在函数执行前/中/后增加其余逻辑代码。 AOP编程的益处是遵循繁多准则,不会批改原函数外部的代码就能够扭转原函数的逻辑。 js中实现AOP应用protoType原型链,例如上面代码 /** * 切入办法前 * @param {Function} fun 前置函数 * @returns */Function.prototype.before = function(fun){ var self = this;// 保留被拦挡函数的this return function(){// 代理函数 fun.apply(this,arguments); var agent = self.apply(this,arguments);// 返回代理函数 return agent; }}/** * 切入办法后 * @param {Function} fun 后置函数 * @returns */Function.prototype.after = function(fun){ var self = this;// 保留被拦挡函数的this return function(){// 代理函数 var agent = self.apply(this,arguments);// 返回代理函数 fun.apply(this,arguments); return agent; }}// 业务代码function logic(){ console.log('业务代码');}// 切入logic = logic.before(function(){ console.log('切入前');}).after(function(){ console.log('切入后');})// 测试logic();下面办法通过返回一个代理函数的形式,奇妙的实现链式编程。 ...

March 31, 2021 · 1 min · jiezi

关于设计模式:使用策略模式实现表单验证

应用策略模式实现表单验证1.什么是策略模式策略模式说起来很高大上,其实现实生活中很常见。比方,你要从老家去北京故宫玩耍,可选的出行形式有坐火车、开车自驾、坐飞机等几种形式,至于抉择哪种呈现形式要看本人的经济能力和集体需要,而抉择的过程就是一种策略模式。 2.利用例子-表单验证在js代码中如何实现策略模式? 1.你得有一堆可供选择的策略strategies = [one, two, three,...]2.依据不同的场景Context应用不同策略。上面我应用策略模式实现登录界面的表单验证,如果不合乎规定,进行弹窗提醒 <!DOCTYPE html><html lang="en"><head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /></head><body> <h1>登陆</h1> <form id="registerForm"> <span>请输出用户名:</span><input type="text" name="userName" placeholder="不能为空"/> <br /> <span>请输出明码:</span><input type="text" name="password" placeholder="起码6位"/> <br /> <span>请输出手机号码:</span><input type="text" name="phoneNumber" placeholder="请输出正确的手机号码"/> <br /> <button>登陆</button> </form></body><script src="./index.js"></script></html>1.把策略筹备好,策略就是校验规定const strategies = { isNoEmpty: function(value, errorMsg) { return value ? '' : errorMsg }, minLength: function(value, errorMsg,length) { return value && value.length >= length ? '' : errorMsg }, isMoble: function(value, errorMsg) { return /(^1[3|5|8][0-9]{9}$)/.test(value) ? '' : errorMsg; }}2.再写一个Context// 校验类const Validator = function(){ this.rules = [];// 校验规定}Validator.prototype.add = function(dom, rule, errorMsg){ const key = Object.keys(rule)[0]; const value = rule[key] this.rules.push(function(){ return strategies[key].apply(null, [dom.value, errorMsg, value]) })}Validator.prototype.run = function(){ for(let i = 0; i < this.rules.length; i ++){ const msg = this.rules[i]() if (msg) return msg; }}3.业务代码// 进行校验const validateLoginData = function(){ const validator = new Validator() validator.add(document.getElementsByName('userName')[0], {isNoEmpty: true}, '用户名不能为空') validator.add(document.getElementsByName('password')[0], {minLength: 6}, '明码起码6位') validator.add(document.getElementsByName('phoneNumber')[0], {isMoble: true}, '手机号不正确') return validator.run();}// 绑定事件window.onload = function(){ document.getElementById('registerForm').onsubmit = function(){ console.log('xxxx') var errorMsg = validateLoginData() if(errorMsg){ alert(errorMsg) return false; } }}

March 18, 2021 · 1 min · jiezi

关于设计模式:浅谈设计模式-模板方法十

浅谈设计模式 - 模板办法(十)前言: 模板办法模式在JAVA当中最为熟知的就是spring的template对象,模板办法和策略这两个模式须要小心的辨别,对于模板办法模式只须要重点记忆一句话:模板办法的模式定义了算法的骨架。同时针对模板办法的的一项设计准则好莱坞准则也是对 依赖倒转准则一种很好的补充和扩大。 文章目标:理解模板办法,同时理解模板办法是如何体现好莱坞准则的。模板办法与策略模式的比照,以及模板办法灵活运用钩子函数。模板办法的简略案例,以及在spring框架当中的具体体现。什么是模板办法根本定义定义:在一个办法当中定义了算法的骨架,而将具体的实现提早到子类当中。模板办法在不扭转算法构造的状况下,重构算法的某些步骤。 从事实看模板办法 咱们都晓得古代各式各样的蛋糕都是应用模具做成的,而同一个形态的蛋糕却能够应用不同的配料,此时模具便是模板办法的骨架,通过定义具体的配料细节对应了“算法”的细节。 钩子函数 钩子函数是一种编程上比拟罕用的技巧,在框架设计当中非常常见,什么是钩子呢?从集体的了解来看,钩子像是能够提早定义的匿名函数,钩子能够“勾”住某个算法的两头过程,让外部环境能够干预外部算法实现的同时,又能让外部的函数进行自在管制钩子的应用。 钩子函数个别实现形式为抽象类或者不做任何动作的函数。 钩子函数在脚本语言外面常常被用作回调函数。包含java的许多框架也用钩子让用户能够干预一些算法的细节。然而须要留神的是,钩子这个货色很容易毁坏代码的可浏览性,所以不倡议常常应用这种函数,能够用组合以及其余的设计模式对于构造进行优化。 模板办法的结构图 上面是模板办法的结构图,模板办法比照其余设计模式应该算是最简略的一个结构图了,比拟容易了解: 模板办法的模式定义了算法的骨架,那么什么是定义算法的骨架,从上面的图表很好的看到,父类定义为抽象类,定义模板的算法办法和形象的算法细节。 这里要实现算法须要由子类实现具体的算法业务 模板办法的优缺点长处: 模板办法能够让算法的细节覆盖在子类,同时抽取公共的算法,进步代码复用水平模板办法能够让批改管制在子类,而父类办法不须要进行改变,合乎凋谢敞开准则。毛病: 模板办法类的改变对于所有的算法实现子类都会产生影响,同时模板父类改变违反“凋谢-敞开”准则模板办法因为利用钩子管制父类办法,会导致反向控制代码,对于代码的浏览不是非常敌对。模板办法与好莱坞准则什么是好莱坞准则? 首先须要理解一下什么是好莱坞准则:**让咱们调用你们,而不是让你们调用我**。和依赖倒转准则有什么关联? 好莱坞准则更像是对于依赖倒转的一种扩大技巧。依赖倒转更加关注的是如何在设计中防止面向实现编程,而好莱坞则是将实现的调用在低层的构造进行暗藏。 为什么不倡议低层组件调用高层组件? 为了避免环形依赖,在高层组件外面调用了形象办法,而形象办法又调用高层组件的办法。 策略模式和模板办法比照策略模式和模板办法模式的比照 策略是定义一整个算法,应用组合的模式实现不同的对象切换模板办法的是定义一个超类,在超类中通过高层调用底层实现的具体方法的实现,来实现办法的提早性能案例 这次的案例以集体小时候做过的一件事件举例,以前外婆兼职从厂里拿来一堆玩具整机的成品,而工作就是把成品进行“反转”(就是把做好的玩具翻面),还十分分明的记得大略是一分钱一个,靠着帮忙那时候还拿了一些零花钱,每天放学做完作业之后就是帮外婆做“兼职”。这种重复性劳动,在代码的构建很容易想到模板办法的模式,因为各种玩具的形态不同,所以翻面的形式以及效率和速度都不同,咱们将重复劳动的局部定义为顶层的模板,而具体的玩具构建细节,须要依据不同的玩具进行不同的操作,上面定义这个工作的大抵流程: 上面是依据结构图绘制一个根本的代码: // 玩具制作模板类public abstract class TemplateWorkFlow { public void productToy(){ takeToy(); reverseToy(); putBasket(); } public final void putBasket() { System.out.println("把玩具放到玩具篮"); } public void takeToy(){ System.out.println("拿起玩具"); } public abstract void reverseToy();}public class AntlersToyWorkFlow extends TemplateWorkFlow { @Override public void reverseToy() { System.out.println("把骨干翻面"); System.out.println("把鹿角的分叉翻页"); }}public class ChristmasHatWorkFlow extends TemplateWorkFlow{ @Override public void reverseToy() { System.out.println("圣诞帽反转"); System.out.println("圣诞帽帽子顶部的小秋顶进来"); }}public class Main { public static void main(String[] args) { TemplateWorkFlow templateWorkFlow = new ChristmasHatWorkFlow(); TemplateWorkFlow templateWorkFlow1 = new AntlersToyWorkFlow(); templateWorkFlow.productToy(); templateWorkFlow1.productToy(); }/* 拿起玩具 圣诞帽反转 圣诞帽帽子顶部的小秋顶进来 把玩具放到玩具篮 拿起玩具 把骨干翻面 把鹿角的分叉翻页 把玩具放到玩具篮 */}如果不应用设计模式,他大抵的设计代码如下,能够看到很多办法都干了类似的事件,这些办法可能实质上只是一两行代码甚至只是取名不一样,当然古代的编译器都很“聪慧”,会发现反复的点,所以最最根本的要求,是编写出编译器都无奈发现的反复代码,当然仅仅凭借这一点显然要求有点低 ...

March 7, 2021 · 2 min · jiezi

关于设计模式:设计模式

什么是设计模式?设计模式是一套被重复应用的、通过分类编目标、代码设计教训的总结,应用设计模式是为了可重复使用代码,让代码更容易被别人了解并且进步代码的可靠性。 能够说设计模式是在特定环境下为解决某一通用软件设计问题提供的一套定制的解决方案,该计划形容了对象和类之间的相互作用。 基本要素名称模式名称是用来反映形容模式的问题,解决方案和成果,不便开发人员之间的交换与更好的了解设计模式,大多数设计模式都是依据性能来命名的,如xxxFactory。 问题形容了应该在何时应用模式,蕴含了原始设计中存在的问题以及问题存在的起因。 解决方案形容了设计模式的组成部分,以及这些组成部分之间的互相关系,各自的职责和合作形式。 成果形容了设计模式的利用状况以及在应用模式时应该衡量的问题,蕴含设计模式的优缺点。没有任何一个解决方案是完满的,因而在抉择设计模式的时候须要进行正当的抉择。 设计模式的分类能够依据目标(用来做什么的)分类,将模式分为:创立型、结构型、行为型。也能够依据范畴(解决类之间的关系还是解决对象之间的关系)分类,将模式分为:类模式、对象模式,如下所示: 设计模式阐明形象工厂模式提供一个创立一系列相干或相互依赖对象的接口,而无需指定它们具体的类 建造者模式将一个简单对象的构建与它的体现拆散,使得同样的构建过程能够创立不同的示意 工厂办法模式定义一个用于创建对象的接口,然而让子类决定将哪一个类实例化。工厂办法模式将一个类的实例化提早到其子类 原型模式应用原型实例指定待创建对象的类型,并且通过复制这个原型来创立新的对象 单例模式确保一个类只有一个实例,并提供一个全局拜访点来拜访该实例 适配器模式将一个类的接口转换成客户心愿的另一个接口,适配器模式让那些接口不兼容的类能够一起工作 桥接模式将形象局部与实现局部解耦,使得两者都可能独立变动 组合模式组合多个对象造成树形构造以示意具备局部-整体关系的层次结构。组合模式能够让客户端对立看待单个对象和组合对象 装璜模式动静的给一个对象减少一些额定的职责,就扩大性能而言,装璜模式提供了一种比应用子类更加灵便的代替计划 外观模式为子系统中的一组接口提供对立的入口,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易应用 享元模式使用共享技术无效地反对大量细粒度对象的复用 代理模式给某一个对象提供一个代理或占位符,并由代理对象来管制原对象的拜访 责任链模式防止一个申请的发送者和接收者偶合在一起,让多个对象都有机会解决申请。将接管申请的对象连接成一条链,并沿着这条链传递申请,直到有一个对象可能解决它为止 命令模式将一个申请封装成一个对象,从而可用不同的申请对客户进行参数化,对申请排队或者记录申请日志,以及反对可撤销操纵 解释器模式给定一种语言,定义它的文法的一种示意,并定义一个解释器,这个解释器应用该示意来解释语言中的句子 迭代器模式提供一种办法程序拜访一个聚合对象中的各个元素,而又不裸露该对象的外部示意 中介者模式定义一个对象来封装一系列对象的交互,中介者模式使各个对象之间不须要显示地互相援用,从而使其耦合涣散,让你能够独立地扭转它们之间的交互 备忘录模式在不毁坏封装的前提下,捕捉一个对象的外部状态,并在该对象之外保留这个状态,这样能够在当前将对象复原到原先保留的状态 观察者模式定义对象之间的一种一对多的依赖关系,使得每当一个对象状态产生扭转时,其相干依赖对象皆失去告诉并被自动更新 状态模式容许一个对象在其外部状态扭转时扭转它的行为 策略模式定义一系列算法,将每一个算法封装起来,并让它们能够互相替换,策略模式让算法能够独立于应用它的客户变动 模板办法模式定义一个操作中算法的框架,而将一些步骤提早到子类中,模板办法模式使得子类能够不扭转一个算法的构造就能够重定义该算法的某些特定步骤 访问者模式示意一个作用于某对象构造中的各个元素的操作,访问者模式让你能够在不扭转各个元素的类的前提下定义作用于这下元素的新操作 设计模式的长处交融了泛滥专家的教训,并以一种规范的模式给宽广开发人员应用,提供通用的设计词汇和开发语言,不便开发人员交换。让设计方案更加通俗易懂,使不同编程语言的开发和设计人员能够通过设计模式来交换零碎设计方案,设计模式能够升高开发人员了解零碎的复杂度。让开发人员能够更简略地复用胜利的设计和体系结构,使得重用胜利的设计更加容易,并防止导致不可重用的设计方案。让设计方案更加灵便,易于批改。在很多设计模式中宽泛应用了开闭准则、依赖倒置准则等面向对象设计准则,让零碎有较好的可维护性,真正实现了可维护性的复用。在软件开发中正当应用设计模式,能够使零碎中的一些组成部分在其它零碎失去重用,而在此基础上进行二次开发天然不便得多。设计模式是通过屡次实践证明的无效解决方案,且通常是针对某一类问题的最佳设计方案,因而设计模式的应用进步软件系统的开发效率和软件品质,在肯定水平上节约设计老本。有助于开发人员更深刻地了解面向对象思维,还能够进步开发人员的设计程度和代码品质。

March 6, 2021 · 1 min · jiezi

关于设计模式:微服务设计模式概述笔记

模式分为三组: 基础设施相干模式:基础设施相干;利用基础设施相干:利用层面基础设施;利用相干模式组;各模式合成服务拆分模式依据业务能力合成模式依据子域合成模式通信相干通信格调服务发现可靠性事务性音讯内部API数据一致性解决分布式日志,以及数据一致性; 查问数据解决多个服务数据源获取数据;CQRS: 命令查问职责隔离 服务部署解决微服务如何部署;可食用 虚拟机,容器,serverless技术; 可观测性了解和诊断微服务架构,包含: 健康检查API日志聚合分布式追踪异样跟踪利用指标审计日志

March 3, 2021 · 1 min · jiezi

关于设计模式:浅谈设计模式-适配器模式八

浅谈设计模式 - 适配器模式(八)前言:适配器模式大略是零碎用的最多的模式,在spring框架当中能够看到他的各种利用,比方咱们想要注册本人的拦截器,或者须要沿用旧接口实现一些本人的实现,都能够应用适配器模式进行实现,适配器模式是一种十分贴合起码常识准则的设计模式,这篇文章将会具体介绍一下适配器模式。 文章目标:理解什么是适配器模式适配器模式的优缺点实战,理解适配器模式什么是适配器模式?定义:在不改变客户代码的状况下实现一个接口向另一个接口的自在转化,让本来不能适配的接口具备类似的性能。 适配器存在三个角色,客户端,适配器,被适配者。适配器实现目标的接口,并且持有被适配者的实例 适配器模式是一种:行为型模式。因为他将一个接口的行为转化为另一个接口的行为。 适配器模式优缺点:先说说适配器模式的长处: 能够让客户从接口的实现当中解放让客户由本来的面向实现转变为面向接口让被适配对象具备接口性能的同时能够实现自在的扩大上面说说毛病,其实适配器的毛病也比拟显著: 因为JAVA不反对多继承,无奈实现多个对象的适配工作,只能应用多接口的模式适配,实现起来要比其余的语言略微简单一些。适配器最难改变的中央在于适配指标的办法,假如适配指标的办法组合了多个被适配对象,此时改变任意一个被适配对象,都会对适配的办法带来影响,同时适配办法也是最难以改变的。对于适配器应用的倡议: 一个适配器最好做一个类的适配工作。如果一个适配器须要适配多个类,须要思考是否存在关联性能够应用双向接口适配器,既能够实现旧接口的办法不改变,同时实现新接口的新实现。要做到这一步,要害是确保:两个接口应用继承还是应用组合 对于适配这一个概念,咱们能够应用两种模式:继承 和 组合 首先说下继承,继承是指对于一个类进行“超类”的扩大,如果此时咱们应用继承的模式去扩大指标对象,尽管从实践上能够实现一个适配器间接具备两个对象的性能,然而因为JAVA自身是不反对多继承的,同时多用组合,少用继承是软件设计行业一条十分推崇的定律。所以继承的模式“不太敌对”。 再说下应用组合的模式,组合是比拟推崇的模式,咱们在实现目标接口的根底之上,组合被适配的对象,让旧接口的性能能够兼容新接口的实现。这也是JAVA代码当中常常会见到的一种模式,同时在框架中以相似“套版”的模式呈现。 适配器模式的特点:适配器的实现就是把客户类的申请转化为对适配者的相应接口的调用,当客户端进行申请的时候,指标对象通过适配器,将申请的逻辑转变为“适宜”被适配对象的申请,由适配器实现这一转化细节,适配过后执行被适配对象的性能,这种转化对于客户端来说是荫蔽的,同时会让客户端误认为是指标对象实现的了工作,所以这种模式的最大特点是:申请代码能够齐全不须要扭转。 适配器模式了解上面依据适配器模式,介绍一下集体对于适配器模式的一些了解。 从插头引申适配器模式 插头有很多中标准,然而日常生活罕用的插头个别是两孔或者三孔的插头,个别状况下一个新厂商的插头须要兼容旧厂商生产的插头,同时须要兼容旧厂商的办法,不想扭转旧厂商的实现状况下,须要实现新厂商的实现,这时候通常须要依赖一个适配器去做适配,适配器如同一个两头通信人,能够将看起来毫不相干的两个对象之间产生肯定的关联个性。 单向适配和双向适配 须要留神的是适配器模式肯定不要教条的认为只能单向的适配,适配器是能够进行双向适配的,然而此时咱们通常须要两个接口来实现双向的适配。 适配器模式和起码常识准则适配器模式对应的一个软件设计准则是:起码常识准则 起码常识准则:接口负责尽可能少的性能。用文言来讲就是简洁 遵循起码常识准则对于任何对象,在他的办法内他应该做这些事件 只操作对象本人自身传递的对象参数或者和该对象返回的后果对象(然而会有依赖传递的问题)办法自身创立的对象对象的任何组件:HAS-A(组合)的外部对象这里须要小心依赖磁铁,也就是依赖了依赖对象的对象,简略了解就是应用了其余对象返回的另一个对象,这种状况很容易被忽视,而且通常状况下是 不会呈现问题的,然而一旦要进行重构,这种代码就很容易造成逻辑凌乱。适配器的调用流程客户端通过指标接口调用适配器的办法发送对应的申请。适配器用适配办法转化为一个或者多个被适配器的多种办法客户端失去的接口会误以为是指标对象在工作。同时不须要进行任何变动就能够实现新的性能或者办法。适配器模式的结构图上面是适配器模式的结构图: + client 客户端+ Target 指标接口,+ Adapter 适配器,负责将两个对象进行关联,产生类似的业务+ Appropriate object 被适配对象,代表了须要适配的对象内容下面的结构图展现了如何指标接口转化为被适配对象的行为。 实战说了不少的实践内容,上面咱们依据一个模仿场景制订一份适配器的代码: 模仿场景 在任天堂发售的switch在日版和港版的两个版本当中,充电充电器的设计是不一样的,因为港版沿用了英国应用的是三插式(大部分电器都是这种状况),而我国应用的是较为通用二插式,日本在设计的时候也是应用二插式,所以在充电器的设计下,日本不须要进行适配,间接能够插到我国的插座上,而港版通常须要购买转接头或者买其余的适配器。 不应用设计模式 笔者在构思这一块没有思考好不应用设计模式如何实现,其实这种状况下,不应用设计模式最好方法通常就是找一个第三方工具进行代替,比方咱们能够买一个switch的充电宝,每次充电只有充充电宝就行了,连充电器都省了...... 应用设计模式 还是间接从设计模式开干把,很显然,既然港版都是用的转接头,那么咱们的代码就应用转接头来实现这一块的性能: 上面是依据模仿场景进行剖析,咱们按照适配器的结构设计出根本对象: switch:咱们权且把它设想是客户端,咱们把它设想成一个想要充电的“人”。发动了充电这一个申请来匹配适合的充电器JapanMouth:日版充电器,间接对标国内的插口Mouth:插口接口。EngMouth:英式插口,依照英国的规范设计的插口。Adapter:适配器,在这里充当的是转接器,负责转接插口有了下面这些定义,上面依据具体的设计出代码: public class Switch { private TwoHoleCharge twoHoleCharge; public Switch(TwoHoleCharge twoHoleCharge) { this.twoHoleCharge = twoHoleCharge; } /** * 模仿充电办法 */ public void recharge(){ twoHoleCharge.jack(); } public TwoHoleCharge getTwoHoleCharge() { return twoHoleCharge; } public void setTwoHoleCharge(TwoHoleCharge twoHoleCharge) { this.twoHoleCharge = twoHoleCharge; }}// 插口接口public interface Mouth { void jack();}public class JapanMouth implements Mouth { public void jack(){ System.out.println("日版:开始充电"); }}public class EngMouth { public void specialJack(){ System.out.println("港版:开始充电"); }}//==要害==适配器public class Adapter implements Mouth { private EngMouth engMouth; public Adapter(EngMouth engMouth) { this.engMouth = engMouth; } @Override public void jack() { engMouth.specialJack(); }}public class Main { public static void main(String[] args) { // 日版插口能够间接应用 Mouth mouth = new JapanCharge(); Switch aSwitch = new Switch(mouth); aSwitch.recharge(); // 港版插口须要转接口 Mouth mouth2 = new Adapter(new EngMouth()); aSwitch.setMouth(mouth2); aSwitch.recharge(); }/*运行后果: 日版:开始充电 港版:开始充电 */}代码比较简单,应该比拟好了解,这里重点关注一下Adapter的适配器对象,通过组合的模式,将被适配对象“暗藏”到了指标对象的办法外部,实现了接口的适配,客户在应用的时候,只须要用一个适配器就能够让港版能够间接兼容到国内的电网。 ...

March 3, 2021 · 1 min · jiezi

关于设计模式:如何从分类层面深入理解设计模式

文章首发于公众号「架构师指南」及集体博客 shuyi.tech,欢送关注拜访。 学习过设计模式的都晓得,设计模式分为三大类,别离是:创立型、结构型、行为型。但为什么它们这么分呢?某个设计模式为啥就属于结构型,而不属于行为型呢?创立型、结构型、行为型它们到底有什么不同呢?明天就来聊一聊我的了解。 创立型模式创立型模式,顾名思义就是用来创建对象的。 创立型模式蕴含的五个设计模式,别离是: 从它们的作用来看,它们全部都是创立新对象相干的模式。 工厂办法模式、形象工厂模式、建造者模式都是创立新对象,能够屏蔽创建对象的细节。原型模式是进行对象克隆,也算是新对象创立。单例模式是管制只能创立单个对象,其也蕴含了对象的创立,因而也算是创立型模式。 结构型模式结构型模式,就是介绍如何将对象和类组装成较大的构造,并同时放弃构造的灵便和高效。结构型模式把一个个对象联合在一起,就像积木搭建起来一样,有一种结构化的感觉。 结构型模式蕴含 7 个设计模式,别离是: 适配器模式 指的是能够让不兼容的对象可能单干,通常状况是有一个适配器类实现了多个接口,从而在接口办法中写入特定逻辑去做兼容适配。这里的构造体现在对于两种对象的兼容,通过兼容将新老对象组合起来了。 桥梁模式 其实就是把固定的和变动的拆散开来,应用组合的形式去实现。将固定的放在原地不动,而变动的则抽离进来作为一个新的类,再通过组合的模式被老的类援用。这里的构造体现在旧类对新类的援用,它们之间变成了一种结构型关系。 组合模式 就是多个构造组合起来,造成一个更简单的构造。组合模式更多是一种数据结构的出现,而不能说是一种设计模式。但从狭义的设计模式定义来看,将组合模式说成是一种设计模式,也没有错。 大家会发现组合模式和桥梁模式十分像,其实这两者之间并没有太大的差异,甚至是说根本一样。桥梁模式与组合模式,其实都是基于组合这种关系,不同的对象组合起来造成更大的构造体。桥梁模式是基于组合模式的。 装璜模式 指的是应用很多其余类对原有类进行性能加强,就像美颜APP一样,咱们应用很多滤镜对照片进行性能加强。这一个个的滤镜就嵌套在原有的照片上,就像一个个性能加强类嵌套在原有的根底类上一样。装璜模式的结构性就体现在这种嵌套关系上,一层层的嵌套组成了一种构造。 门面模式 指的是提供一个全新的接口层,将子系统简单的接口内容屏蔽了。则像是肯德基的前台一样,帮你把所有简单的货色屏蔽了。你不须要关怀汉堡怎么做,奥尔良鸡翅怎么做。你只须要通知前台要吃什么,它就会把汉堡、鸡翅等货色做好了拿给你。 在门面模式中,咱们在应用方与子系统之间插入了一层接口层,去屏蔽简单的外部细节。就像是肯德基的前台,帮咱们屏蔽了外部食物的制作细节一样。门面模式的构造就体现在咱们插入的这一层「门面」上,它将应用方与子系统连接起来,让应用更不便了! 享元模式 指的是共享同一个元素,是一种节俭内存的设计模式,其实就相似咱们的池技术。与其余对象简单的构造相比,我都不感觉享元模式是一种设计模式,而只是一种思维而已。但如果严格地从设计模式的定义来讲的话,那其实也能够算是。 在享元模式中,咱们会新增一个类去保留元素的映射池。而这个新增的类就相当于是一个新增的对象,通过组合的模式去节俭内存的耗费。享元模式的结构性更多是通过组合的模式体现的。 代理模式 其实就是一个代理卡在买卖双方两头,做一些流程上的管制。代理模式的结构性就体现在多了一个代理类,卡在「买卖双方」两头,这种结构特征显而易见。 从下面咱们的形容来看,咱们能够晓得结构型模式很多时候,就是两者对象之间有一个对象挡在两头,例如:适配器模式、门面模式、代理模式。要不就是通过某些关系组合在一起,例如:桥梁模式、组合模式、装璜模式、享元模式。 行为型模式要了解行为型模式,就要重点注意行为。尽管行为型模式有些点与结构型模式相似,然而其最大的特点是行为,是这个动起来的货色。 咱们举个例子:为什么中介者模式属于行为型模式,而代理模式属于结构型模式? 中介者模式听起来与代理模式很像,但中介者模式说的是做多个对象之间的协调工作,协调他们的口头!看到了吗?协调他们的口头,才是中介者模式的外围,所以说中介者模式才是行为型模式。而代理模式,则不会有那么多个对象之间简单的关系,其侧重于对被代理对象的管制。其重点不在于简单的对象关系,不在于协调多个对象的工作,而在于单个对象的管制,代理就像卡在两者两头的一个构造一样。 有些敌人要说了,那其实代理模式也有对代理对象的管制这一行为啊,为什么不能算是行为型模式呢?代理模式的确有对代理对象管制这一行为,但这里要强调的是重点这个词。这里并不是说代理模式就没有行为,而是说代理模式的行为比起结构性少,并且不是重点。而中介者模式必定也有结构性的货色,但它诞生的目标就是为了协调多个子系统的简单调用关系,协调关系才是中介者模式的重点。 行为型模式有 10 个设计模式,别离是: 责任链模式,是一个个对象组合起来的对象链。 其申请会从链头传到链尾,每个对象能够判断其是否返回或传递到下一个对象。其侧重于是否返回或传递上来,重点是在这个行为的解决。所以责任链模式才叫行为型模式。 命令模式,是把要做的事件形象起来,造成一个命令。 后续要做这个事件的时候,我间接给一个命令你就晓得我要做什么了。为什么要这么做呢?因为变动!如果咱们的命令有很多个,那么每次我批改一个命令,我就要批改收回命令和执行命令两个中央。 但实际上收回命令的动作是不会变的,变动的只是执行命令的中央。于是为了隔离变动,那么咱们将执行命令这块拆散进来。那么收回命令与执行命令怎么沟通呢?答案是通过命令!这个其实就相似于餐厅前台与后厨的沟通。餐厅前台给的做菜单就是一个命令,后厨拿到这个命令之后就去执行。 能够看到在命令模式里,其外围是拿到命令去执行,它们之间也是一个口头的概念,因而命令模式也才归属于行为型模式。 迭代器模式,其实就是实现了汇合所有元素的遍历,让你应用的时候不须要关怀它底层的数据结构。 其重点在于对汇合元素的遍历这个行为,所以归属于行为型模式。在当初基本上只存在于源码、框架中,理论工作用到的很少了。 中介者模式,后面说过了其侧重于对多个对象之间的协调。 其重点在于协调这个事件,所以其归属于行为型模式。 备忘录模式,就是在某个时候把货色记下来,防止遗记了。 在编程上,其实就是在某个时刻将对象的信息记录保留下来,从而在另一个时候能够复原。其重点在于,其实现上会有一个专门的类来帮你记录下信息,所以归属于行为型模式。 观察者模式,从其名字能够晓得有些人盯着你,须要晓得你的动向,其实就是公布订阅模式。 其重点在于察看这个动作,察看之后将这个事件传递进来,你看到这些都是一个个的动作,因而归属于行为型模式。 状态模式,就是更为不便地管制状态。 如果一个事物的状态转换比较复杂,那么能够将其状态抽离进去,独自作为一个类。这样其状态的变动就能够更好地管制,也拆散了变动。这个就是状态模式的利用。从名字来看,咱们会感觉它应该是结构型模式,即蕴含某状态嘛。但实际上,其侧重于对于状态更好地管制,所以归属于行为型模式。 策略模式,其实就是对于不同的货色,用不同的解决形式。 个别状况下,单个具体的策略就是一个类,而这些类都会实现这些策略共有的一个接口。其重点在于不同货色,不同的解决形式。重点在于解决形式的不同,所以归属于行为型模式。 模板办法模式。 这里有两个词,即:模板、办法。模板指的是一套固定的货色,其实就是固定的额算法。办法,示意这个模板是寄存在办法上的。所以叫模板办法。简略地说,模板办法其实就是父类定义了接口类的一些共有算法。子类不能扭转这个算法流程,只能做无限的扩大。所以模板办法的重点是父类管制了一整套行为流程,其外围在于有一套固定了的算法行为,所以叫行为型模式。 访问者模式。 拜访,即当你当成了外人,不想你轻易动。你要什么,我弄好之后给你(调用你的办法)。其定义的还是访问者与被访问者之间应该如何沟通的问题,所以归属于行为型模式。 总结为什么要费尽周折从分类下来说这些设计模式呢?因为这样能更好地了解设计模式。 一个设计模式能归属于某个分类,我置信并不是偶合,必定是因为其个性是合乎这个分类的,不然不可能轻易地进行分类。 所以咱们去钻研为什么这个模式归属于这个分类,能够更好地了解这个模式的实质,使得咱们对这些设计模式有更好的了解。与此同时,咱们在钻研的过程也是深刻了解的过程,也是比照的过程,一直加深咱们的了解与认知。 但囿于集体对于常识的了解水平不同,可能我在某些模式上的了解也并不是很透彻,有些解释可能会有点牵强,甚至顾名思义。所以大家看的时候还是得批判性地读。如果有更好的解释,能够留言通知我,咱们一起深刻探讨。

February 26, 2021 · 1 min · jiezi

关于设计模式:浅谈设计模式-命令模式七

浅谈设计模式 - 命令模式(七)前言:命令模式也是一种比拟常见的行为型模式,能够设想咱们的手机智能遥控器,通过按动按钮的模式开启各种家具,说白了,就是将一系列的申请命令封装起来,不间接调用真正执行者的办法,这样比拟好扩大。须要留神的是命令模式和策略模式类似,所以有时候可能容易弄混,这篇文章将会具体介绍命令模式 文章目标:理解命令的模式的特点简略比照命令模式和策略模式命令模式的优缺点总结什么是命令模式?解释:把“申请”封装为对应的对象,应用不同的申请参数化对象,命令模式反对撤销撤销的操作 命令模式是一种行为型模式,实现了接口调用对象和返回对象,用命令对象作为桥梁实现调用者和具体实现者之间的解耦和交互。 命令模式的特点:将发出请求的对象和执行申请的对象解耦调用者能够自在定义命令参数进行自在的组合命令能够用来实现日志或者事务零碎(undo操作)命令模式结构图:上面依据命令模式的定义,以及下面对于命令模式的了解,构建具体的结构图 + Client 客户端:客户端须要创立具体的命令类,并且通过发送申请给执行者调用具体的对象,发送方和接管方不存在关联,对立由命令对象进行连贯。 + Invoker 执行者:申请的发送者,负责将申请分发给具体的命令实现类,由实现类调用理论的执行者进行执行操作 + Command 接口:命令接口,定义命令的标准 + ConcreteCommand 命令接口实现类:实现命令的同时组合具体对象。 + ConcreteObject 具体实现类:定义截图的实现生产对象。 + Receive 执行者:申请的真正执行者,能够是任意对象,通常以 组合模式呈现在执行者的外部 命令模式的了解这里参考《Head firtst设计模式》的案例,模仿具体的交互流程 对象村餐厅交互过程咱们到餐厅点餐,个别会经验如下的流程 客人负责下订单,由服务员承受订单服务器接管订单,调用订单柜台的下订单的办法,不须要关注细节订单柜台告诉厨师进行生产厨师生产订单物品之后,交给服务员上菜依据下面的步骤利用伪代码的体现如下: createCommandObject() 构建命令对象setCommand() 传递命令execute() 命令执行action1(),action2() 执行者理论执行交互流程图咱们依据下面的交互过程介绍,构建具体的交互流程图,咱们能够看到外面有角色:客人、服务员、订单柜台、厨师,他们自身并没有关联,而是通过餐厅的模式彼此产生了具体的关联,同时咱们比照下面的结构图,看下对象村餐厅对应的结构图: 上面依据结构图说一下各种角色的职责: 客人:相当于client客户端,负责指挥服务员进行下单的操作。 服务员:充当申请的发送者,承受客户端的申请,调用下订单的接口到具体的订单柜台,然而不须要关怀具体的细节,只具备下订单这一个操作 订单柜台:通过服务员传递的订单,安顿厨师执行具体的工作 厨师:依据订单柜台的订单做菜,将后果返回给服务员(或客人) 咱们从下面的角色图再来看具体的命令模式定义,能够看到根本都是一一对应的状况。 命令模式和策略模式的比照命令模式和策略模式的结构图有些许的相似,上面咱们来比照看一下这两张图的异同: 策略模式结构图: 命令模式结构图: 相同点: 命令模式通过定义命令标准接口,由子类实现命令的执行细节,策略同样定义策略行为同时用子类实现不同的策略性能命令模式和策略都解耦了申请的发送者和执行者不同点: 命令模式利用了命令组合执行对象的模式执行实现具体实现,而策略模式依附上下文对象进行切换策略模式针对某个对象实现不同的策略成果,而命令模式关注申请发送者和实现者之间的业务解耦组合实战模仿场景: 这次的案例还是模仿《Head First》设计模式的当中对于遥控器遥控电器的一个案例,咱们定义如下的内容: 遥控器:命令的发送方,负责依据不同的操作按钮调用不同的设施工作,生成具体的命令对象调用接口执行具体的命令 命令接口:负责定义命令的实现标准,充当遥控器外面的每一个按钮,对应都有具体的实现 命令实现类:负责实现命令的接口,同时调用具体的实现对象执行命令 实现对象:命令的真正执行者,个别夬在命令实现类的外部,比方电视,灯泡等 不实用设计模式在不应用设计模式的状况下,咱们通常通过对象组合的模式组合不同的实体对象执行命令,上面通过一些简略的代码阐明一下设计的弊病: // 灯泡public class Light { public void on(){ System.out.println("关上灯光"); } public void off(){ System.out.println("敞开灯光"); }}// 电视机public class Television { public void on(){ System.out.println("关上电视"); } public void off(){ System.out.println("敞开电视"); }}// 遥控器public class RemoteControl { private Light light; private Television television; public RemoteControl(Light light, Television television) { this.light = light; this.television = television; } public void button1(){ light.on(); } public void button2(){ television.on(); }}// 单元测试public class Main { public static void main(String[] args) { Television television = new Television(); Light light = new Light(); RemoteControl remoteControl = new RemoteControl(light, television); remoteControl.button1(); remoteControl.button2(); }}/*运行后果:关上灯光关上电视*/从下面的简略代码能够看到,如果咱们持续减少电器,同时减少办法,不仅会导致遥控器要随着电器的改变一直改变,同时每次新增一个电器,遥控器要进行相似“注册”的行为,须要将电器接入到遥控器,这样显然是不合乎逻辑的,因为咱们都晓得,遥控器是单纯的指挥者,他不参加任何命令的操作细节,同时尽管真正工作的办法是具体对象的办法,然而这种模式相似将电器“塞”到了遥控器的外部执行,这样也是存在问题,咱们上面须要批改一下这种重大耦合的设计。 ...

February 24, 2021 · 2 min · jiezi

关于设计模式:2个观点带你重新理解设计模式

文章同步发表于集体博客 shuyi.tech,欢送点击原文跳转浏览。 设计模式说白了就是传统教训的总结,它能让咱们在适合的场景应用适合的模式,从而放慢咱们的编程速度,也能进步零碎的扩展性、稳定性。这里我想就设计模式提出两个观点: 1、设计模式是用来承载简单的业务逻辑的。2、用好设计模式须要从变动的角度去了解业务。 设计模式用于承载简单的业务逻辑如果你的业务非常简单,那么基本上是不须要用到设计模式的。只有当你的业务变得复杂的时候,这才须要用到设计模式。这也是为什么设计模式总是和重构一起被提到,因为重构的时候就阐明这个零碎绝对比较复杂了,不然也不会做崩了。 那为什么说设计模式用于承载简单业务呢? 咱们都晓得设计模式都有一个类图,这些类图其实用于示意这种模式对于变动的拆散(对于变动在下文会说到)。设计模式应用类图来存储简单的业务关系,使得开发者能够专一于业务逻辑的开发,所以说设计模式用于承载简单的业务。 如上图所示是策略模式的类图,Context 类是上下文类,在该类中初始化了具体的策略。Strategy 则是策略接口,ConcreteStrategies 则是具体的策略类。这个类图应用 Strategy 与 ConcreteStrategies 的实现关系,将不同策略隔离开来,开发者不须要去关怀策略彼此的关系。而应用 Context 与 Strategy 的关系隔离开来,开发者不须要去关怀怎么抉择策略。所以说 Strategy 与 ConcreteStrategies 的关系、Context 与 Strategy 的关系(类关系)承载了一些逻辑,而就是我所说的:设计模式承载了简单的业务逻辑。 应用设计模式去承载简单的业务逻辑,有好也有坏,但总体来说益处比拟多。害处就是对初学者十分不敌对,可能他们齐全看不懂代码。益处则是相熟设计模式的人,用设计模式能够高深莫测地晓得业务关系,它们应用设计模式作为语言来表白业务的关系。其次,各块代码之间互相隔离,稳定性、扩展性十分好。 从变动的视角去了解业务我工作了5、6年,本该学什么货色都很快。但我却仍旧花了一两个月的工夫,缓缓推敲每个设计模式的实质。通过一段时间的推敲,我发现了一个了解设计模式的全新视角:变动。 很多时候咱们去了解一个设计模式,咱们不能仅仅晓得它的类图是怎么的,这样的学习齐全流于外表。咱们须要晓得它为什么要这么做?它这样做的起因是什么?它在什么场景下应用?通过这样的一番思考,我发现:所有设计模式的诞生,都是为了隔离变动。 在利用的时候,咱们须要去剖析需要中哪些是变动的,哪些是固定的。而后应用设计模式去承载变动的货色,封装固定的货色。 工厂办法模式,实质上是为了隔离创建者与使用者。为什么?因为创建者可能是多变的,而使用者则是确定的。 形象工厂模式,实质上是为了隔离产品族。为什么?因为产品族绝对是多变的,所以要把变动的货色剥离进来。 桥梁模式,实质上是为了将实现剥离进来。为什么?因为实现是多变的,而形象则是确定的,所以要剥离进来。 代理模式,实质上是为了将多变的管制玻璃进来。为什么?因为代理自身是为了加强对指标对象的管制,那其管制的规范可能就很多,明天可能要这个条件,今天可能要那个条件。因而须要将变动的货色剥离进来,因而有了代理类。有了代理类,咱们不会净化指标类。 责任链模式,变动的是对于责任的解决。 命令模式,变动的可能是命令的具体做法、执行规范。 迭代器模式,不变的是迭代模式,变动的是不同的数据结构,迭代算法不一样。 中介者模式,变动?关联?更多是帮忙梳理关系。 备忘录模式,变动?没有特地大,其实就是对于类的状态记录,独自由一个类来管制。 观察者模式,变动?对于察看后的解决是不同的,是变动的。雷同的是,他们都要察看获取触发。 状态模式,变动的是这些状态。 策略模式,变动的是这些具体的做法。 模板办法,变动的是具体的某个细节实现,不变的是整个流程算法。 访问者模式,变动的是不同的拜访对象,不变的是我本身的解决流程(例如文件树的遍历)。 那咱们应该如何从「变动」的角度去剖析业务呢?有什么可遵循的套路吗?有什么最佳实际吗? 首先,咱们还是应该从业务的复杂度动手,看看业务是否足够简单。设计模式的实质是用来承载简单的业务构造,如果业务目前还不清晰,并且也很简略,那就不要用设计模式了。 其次,咱们还是应该从变动这个角度动手,剖析业务零碎中哪些是变动的,哪些是不变的。这个就要求你对业务十分相熟,只有熟悉业务能力弄清楚变动在哪里。 最初,剖析这种变动的各个实体关系,看看是否合乎访问者模式的特色(有固定的成分,又须要变动,又不是继承关系)。

February 23, 2021 · 1 min · jiezi

关于设计模式:大白话聊访问者模式从入门到实践

文章首发于集体博客 shuyi.tech,欢送拜访更多乏味有价值的文章。 访问者模式,重点在于访问者二字。说到拜访,咱们脑海中必定会想起新闻访谈,两个人面对面坐在一起。从字面上的意思了解:其实就相当于被访问者(某个公众人物)把访问者(记者)当成了外人,不想你轻易动。你想要什么,我弄好之后给你(调用你的办法)。 01 什么是访问者模式?访问者模式的定义如下所示,说的是在不扭转数据结构的提前下,定义新操作。 封装一些作用于某种数据结构中的各元素的操作,它能够在不扭转数据结构的前提下定义作用于这些元素的新的操作。但在理论的利用中,我发现有些例子并不是如此。有些例子中并没有稳固的数据结构,而是稳固的算法。在树义看来,访问者模式是:把不变的固定起来,变动的凋谢进来。 咱们举生存中一个例子来聊聊:某科学家承受记着访谈。咱们都晓得科学家承受拜访,必定是有流程上的限度的,不可能让你轻易问。咱们假如这个过程是:先问科学家的学校经验,再聊你的工作经验,最初聊你的科研成果。那么在这个过程中,固定的是什么货色呢?固定的是承受采访的流程。变动的是什么呢?变动的是不同的记者,针对学校经验,可能会提不同的问题。 依据咱们之前的了解,访问者模式其实就是要把不变的货色固定起来,变动的凋谢进来。那么对于科学家承受访谈这个事件,咱们能够这么将其抽象化。 首先,咱们须要有一个 Visitor 类,这里定义了一些内部(记者)能够做的事件(提学校经验、工作经验、科研成就的问题)。 public interface Visitor { public void askSchoolExperience(String name); public void askWorkExperience(String name); public void askScienceAchievement(String name);}接着申明一个 XinhuaVisitor 类去实现 Visitor 类,这示意是新华社的一个记者(访问者)想去拜访科学家。 public class XinhuaVisitor implements Visitor{ @Override public void askSchoolExperience(String name) { System.out.printf("请问%s:在学校获得的最大成就是什么?\n", name); } @Override public void askWorkExperience(String name) { System.out.printf("请问%s:工作上最难忘的事件是什么?\n", name); } @Override public void askScienceAchievement(String name) { System.out.printf("请问%s:最大的科研成果是什么?", name); }}接着申明一个 Scientist 类,表明是一个科学家。科学家通过一个 accept() 办法接管记者(访问者)的拜访申请,将其存储起来。科学家定义了一个 interview 办法,将拜访的流程固定死了,只有教你问什么的时候,我才会让你(记者)发问。 ...

February 18, 2021 · 2 min · jiezi

关于设计模式:浅谈设计模式-工厂模式六

浅谈设计模式 - 工厂模式(六)前言:在第一篇外面曾经介绍过简略工厂了,然而工厂模式外面不仅仅是简略工厂,还存在工厂办法和形象工厂,并且从严格意义来讲简略工厂不能算是一种设计模式,本次的文章针对工厂的进化来开展讲一讲工厂模式的三种常见模式:简略工厂、工厂办法、形象工厂。 文章目标理解简略工厂这种代码编写模式的长处,回顾工厂模式理解如何从简略工厂扩大到工厂办法以及形象工厂比照工厂办法和形象工厂的异同。总结简略工厂,工厂办法和形象工厂,比照优缺点和特点如何分别工厂模式工厂模式个别从类的命名就能够间接看到含意,所以个别状况下很容易看出工厂模式的利用。 工厂模式次要是负责对象的创立无论是创建者还是使用者,都是针对一个形象对象的实现。工厂模式最关注的是对象是如何创立的而不是对象的应用。它针对的是创立这一个过程。工厂模式的具体介绍简略工厂模式简略工厂模式的介绍:https://juejin.cn/post/692206... 之前文章曾经介绍过简略工厂模式,咱们间接看一下简略工厂是如何设计的,从严格的意义上来说,简略工厂是一种良好的“编程习惯”,他很好的解耦了创建对象和应用对象这两个不同的过程。做到“繁多职责”的准则 从下面的图当中咱们构建根本的工厂类和对应的实现子类以及对应的产品抽象类。 上面回顾一下简略工厂的优缺点 长处: 应用创立工厂的办法,咱们实现了获取具体对象和生产对象的解耦,由生产对象的工厂通过咱们传入的参数生产对应的对象,调用方只须要传递须要生产的对象来实现具体的成果。解耦了创立和被创立的过程。依据不同的逻辑判断生成不同的具体对象。毛病: 每减少一个工厂对象具体的实现类,就须要减少if/else不利于保护大量的子类会造成工厂类的代码迅速收缩和臃肿简略工厂的办法个别解决简略的业务逻辑,如果创立逻辑简单不倡议应用。从下面的优缺点剖析能够晓得,简略工厂并不能齐全解决对象的创立解耦,对于对象的创立细节容易造成耦合,同时如果创立的对象过多容易呈现臃肿的工厂代码。 工厂办法模式工厂办法模式:定义了创建对象的接口办法,然而具体的创立过程由子类来决定。工厂办法将创立的过程提早到子类,工厂办法是对简略工厂的扩大和降级,为了解决简略工厂毁坏了“凋谢-敞开准则”的问题而做的改良。咱们将具体的产品进行了形象的同时,将创建对象的过程提早到子类进行实现。 工厂办法的结构图上面为工厂办法的结构图,咱们由简略工厂转变为工厂办法之后,工厂类定义减少了形象的对象创立办法,由子类通过继承的形式实现工厂的形象办法并且实现本人的构建过程。 + Product 产品类,定义产品的专用办法和抽象类+ ConcreteProduct 产品的具体实现子类,蕴含具体产品的实现+ Factory 工厂类,定义工厂的创立办法以及须要子类继承实现的办法+ ConcreteFactory 工厂的实现类,由子工厂来决定生成的具体产品和定义生产的具体过程。工厂办法的特点上面是工厂办法的具体特点 创立的过程解耦到子类,由子类决定创立的过程和后果具体的产品和工厂之间存在必要关联,同时能够应用任意子类产品进行替换须要依附继承的模式由子工厂来决定生产的过程,子类决定产品创立的后果揭示:子类决定创立的后果并不是字面上的创立,而是由调用者决定的。子类决定的是具体针对哪一个实例进行生产,然而生成的具体后果还是管制在创建者的身上简略工厂和工厂办法有什么区别简略工厂是对产品的创立过程进行“封装”,同时创立新的产品必须改变工厂代码。工厂办法是对简略工厂的降级,工厂办法能够管制具体对象的创立以及由子类来决定具体须要创立哪一个对象。简略工厂只是单纯的解耦创建者和使用者,然而简略工厂无奈扭转创立的后果。形象工厂模式形象工厂模式:提供接口,通过定义形象办法的模式,通过实现具体工厂办法实现创立具体对象家族,同时不须要指定非凡的类。 形象工厂的外部往往应用工厂办法进行实现,两者常常被弄混,从构造上来看,他们最大的区别在于工厂办法往往应用继承实现,而形象工厂往往应用外部继承工厂办法的接口实现。辨别工厂办法和形象工厂也是工厂模式的学习要害。 形象工厂的结构图因为形象工厂更像是对工厂办法的改良,咱们定义形象工厂的结构图,形象工厂的构造相比工厂办法要简单一些: 能够参考形象工厂和工厂办法的结构图,看看两者的异同 + FactoryInterface 形象工厂接口,定义一批形象对象的生产接口 + ConcreteFactoryA 形象工厂实现类A,实现形象工厂接口。 + ConcreteFactoryB 形象工厂实现类B,实现形象工厂接口。+ ProductA 形象产品A,定义公共的形象办法或者专用属性 + ConcreteProductA 具体实现产品A + ConcreteProductA 具体实现产品A+ ProductB 形象产品B,定义公共的形象办法或者专用属性 + ConcreteProductB 具体实现产品B + ConcreteProductB 具体实现产品B形象工厂的特点:所有的具体工厂都实现同一个形象工厂接口。生产的后果实现类能够自在实现具体类或者其扩大类的实例。形象工厂的痛点在于扩大一个新的产品生产会造成所有的具体工厂的改变,也蕴含了产品类的变动。形象工厂往往蕴含了一系列的工厂办法形象工厂和工厂办法的区别形象工厂定义形象接口依附子类实现创立的过程,而工厂办法针对子类实现具体的对象创立细节工厂办法须要应用继承的伎俩实现工厂办法“埋藏”工厂创立具体对象的细节工厂办法对于解决“独立”产品的创立十分无效,而形象工厂往往用于解决生产多个存在关联的产品对象。理论案例仍旧参考坦克大战的案例,介绍如何革新坦克大战的具体代码。 模仿场景仍然以经典的任天堂游戏坦克大战为例,在进入游戏的关卡的时候,会呈现我方的坦克和敌人的坦克,我方坦克和中央坦克不仅形态不同,而且很脆,然而敌人的坦克依据色彩须要打好几枪才会覆灭,那么如果用代码来模仿是什么样的呢? 简略工厂实现:应用简略工厂实现的代码如下: 应用简略工厂类来治理坦克的创立过程,简略工厂顾名思义,就是简略的将创建对象的过程进行治理。 减少工厂类 TankFactory.java 用工厂来治理具体的坦克创立过程: /** * 坦克工厂,专门负责生产坦克 * * @author zxd * @version 1.0 * @date 2021/1/25 22:27 */public class TankFactory { /** * 创立坦克 * @return */ public Tank createTank(String check){ Tank tank = null; if(Objects.equals(check, "my")){ tank = new MyTank(); }else if(Objects.equals(check, "mouse")){ tank = new MouseTank(); }else if (Objects.equals(check, "big")){ tank = new BigTank(); }else { throw new UnsupportedOperationException("以后坦克不反对生产"); } return tank; }}上面是对应的坦克以及坦克的子类实现 ...

February 17, 2021 · 5 min · jiezi

关于设计模式:超易懂原来SOLID原则要这么理解

说到 SOLID 准则,置信有过几年工作教训的敌人都有个大略印象,但就是不晓得它具体是什么。甚至有些工作了十几年的敌人,它们对 SOLID 准则的了解也停留在外表。明天咱们就来聊聊 SOLID 准则以及它们之间的关系。 什么是SOLID准则SOLID 准则其实是用来领导软件设计的,它一共分为五条设计准则,别离是: 繁多职责准则(SRP)开闭准则(OCP)里氏替换准则(LSP)接口隔离准则(ISP)依赖倒置准则(DIP)繁多职责准则(SRP)繁多职责准则(Single Responsibility Principle),它的定义是:应该有且仅有一个起因引起类的变更。简略地说:接口职责应该繁多,不要承当过多的职责。 用生存中肯德基的例子来举例:负责前台收银的服务员,就不要去餐厅开盘子。负责餐厅开盘子的就不要去做汉堡。 繁多职责实用于接口、类,同时也实用于办法。例如咱们须要批改用户明码,有两种形式能够实现,一种是用「批改用户信息接口」实现批改明码,一种是新起一个接口来实现批改明码性能。在繁多职责准则的领导下,一个办法只承当一个职能,所以咱们应该新起一个接口来实现批改明码的性能。 繁多职责准则的重点在于职责的划分,很多时候并不是变化无穷的,须要依据理论状况而定。繁多职责可能使得类复杂性升高、类之间职责清晰、代码可读性进步、更加容易保护。但它的毛病也很显著,就是对技术人员要求高,有些时候职责难以辨别。 咱们在设计一个类的时候,能够先从粗粒度的类开始设计,等到业务倒退到肯定规模,咱们发现这个粗粒度的类办法和属性太多,且常常批改的时候,咱们就能够对这个类进行重构了,将这个类拆分成粒度更细的类,这就是所谓的继续重构。 开闭准则(OCP)开闭准则(Open Closed Principle),它的定义是:一个软件实体,如类、模块和函数应该对扩大凋谢,对批改敞开。简略地说:就是当他人要批改软件性能的时候,使得他不能批改咱们原有代码,只能新增代码实现软件性能批改的目标。 这听着有点玄乎,我来举个例子吧。 这段代码模仿的是对于水果剥皮的处理程序。如果是苹果,那么是一种拨皮办法;如果是香蕉,则是另一种剥皮办法。如果当前还须要解决其余水果,那么就会在前面加上很多 if else 语句,最终会让整个办法变得又臭又长。如果恰好这个水果中的不同种类有不同的剥皮办法,那么这外面又会有很多层嵌套。 if(type == apple){ //deal with apple } else if (type == banana){ //deal with banana} else if (type == ......){ //......}能够看得出来,下面这样的代码并没有满足「对拓展凋谢,对批改关闭」的准则。每次须要新增一种水果,都能够间接在原来的代码上进行批改。长此以往,整个代码块就会变得又臭又长。 如果咱们对剥水果皮这件事件做一个形象,剥苹果皮是一个具体的实现,剥香蕉皮是一个具体的实现,那么写出的代码会是这样的: public interface PeelOff { void peelOff();}public class ApplePeelOff implement PeelOff{ void peelOff(){ //deal with apple }}public class BananaPeelOff implement PeelOff{ void peelOff(){ //deal with banan }}public class PeelOffFactory{ private Map<String, PeelOff> map = new HashMap(); private init(){ //init all the Class that implements PeelOff interface }}.....public static void main(){ String type = "apple"; PeelOff peelOff = PeelOffFactory.getPeelOff(type); //get ApplePeelOff Class Instance. peelOff.pealOff();}下面这种实现形式使得他人无奈批改咱们的代码,为什么? ...

February 10, 2021 · 2 min · jiezi

关于设计模式:浅谈设计模式-装饰器模式五

浅谈设计模式 - 装璜器模式(五)前言: 装璜器模式是是对类进行加强的一种典型设计模式,它容许对于一个现有类进行加强的操作,对于喜爱应用继承的搭档,这个模式十分贴切的展现的了对于继承的灵便用法。然而装璜器模式同样不是一个推崇应用的模式,因为他对于继承存在依赖性,从本文后续就能够理解到装璜类收缩的问题,所以在设计代码构造的时候,装璜器模式并不是第一思考。 什么是装璜器模式? 装璜器模式:对现有类不改变构造的状况下为类增加新职责和性能的模式。 动静的扩大类的职责,装璜器模式是一种是比继承更加灵便的代码扩大模式。同时装璜类之间能够进行相互的嵌套 装璜器模式的结构图: Component 装璜接口:装璜接口定义了装璜的顶层形象行为,个别定义被装璜者和装璜者的专用行为 ConrecteComponent 被装璜类:次要为被装璜类实现,和装璜类互相独立,领有独自的性能办法Decorder 装璜器:定义了装璜的通用接口,蕴含装璜器的通用办法 ConrecteDecorderA 装璜器A:定义了装璜器的具体设计,能够蕴含本人的装璜办法ConrecteDecorderB 装璜器B:定义了装璜器的具体设计,能够蕴含本人的装璜办法装璜器模式的特点装璜者和被装璜者都须要实现雷同的接口(必要条件)装璜者个别须要继承一个抽象类,或者须要定义形象的办法和实现装璜者能够在所委托被装璜者的行为之前或之后,加上本人的行为,以达到特定的目标。任何父类呈现的中央都能够用子类进行替换,在活用继承的同时能够灵便的扩大。什么时候应用装璜器模式须要大量的子类为某一个对象进行职责加强的时候,能够应用装璜器模式心愿应用继承对于类进行动静扩大的时候,能够思考应用装璜器模式理论案例:模仿场景:咱们用一个奶茶的构造来模仿一个装璜器的设计场景,咱们通常在奶茶店点奶茶的时候,对于一杯奶茶,能够增加各种配料,这时候配料就是奶茶的装璜者,而奶茶就是典型的被装璜者,咱们应用配料去“装璜”奶茶,就能够失去各种口味的奶茶。同时能够计算出奶茶的价格 上面咱们来看一下针对模仿场景的案例和应用: 不应用设计模式: 不应用设计模式,咱们的第一思考就是简略的应用继承去设计装璜类,咱们通过各种子类组合来实现一杯杯不同口味的奶茶,从上面的结构图能够看到,将被装璜类定义为独立的类,同时不进行任何的继承而是作为独立的类应用。而调料也就是奶茶饮料的配料须要继承同一个抽象类,同时在外部实现本人的办法。 紧接着,咱们在装璜者的办法中引入被装璜者,能够通过外部组合被装璜者进行 模拟行为的同时进行加强,就像IO当中的Buffer。 咱们依据下面的阐明画出这一种设计的大抵结构图: 看了下面的设计图稿之后,咱们来阐明一下具体的代码实现: 首先是奶茶实体类:在奶茶的实体类外面定义两个属性, 应用一个display()打印信息,奶茶的实体类示意被装璜类 /** * 奶茶实体类 * * @author zxd * @version 1.0 * @date 2021/2/7 22:21 */public class MilkTea { private String name; private double price; public MilkTea(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public void display() { System.out.println("name = "+ name + " price = " +price); }}上面是柠檬汁的被装璜类,这个被装璜类也是独立的: ...

February 8, 2021 · 4 min · jiezi

关于设计模式:多线程下的单例模式

前几天去某云面试,面试官问到单例模式,天然陈词滥调的,最初面试官问我,有没有理解过多线程模式下的单例模式?我就懵了,接触最多的PHP和JS都是单线程的,之前也没思考过线程平安的问题,回来查了查资料,特总结如下:(PS:下文java代码来自安卓共事解说) 1.线程平安多个线程拜访同一个对象时,如果不必思考这些线程在运行时环境下的调度和交替执行,也不须要进行额定的同步,或者在调用方进行任何其余操作,调用这个对象的行为都能够取得正确的后果,那么这个对象就是线程平安的。 或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行后果存在二义性,也就是说咱们不必思考同步的问题。 线程平安问题大多是由全局变量及动态变量引起的,局部变量逃逸也可能导致线程平安问题。 若每个线程中对全局变量、动态变量只有读操作,而无写操作,一般来说,这个全局变量是线程平安的;若有多个线程同时执行写操作,个别都须要思考线程同步,否则的话就可能影响线程平安。 2.线程不平安的单例不平安的单例就是动态单例在多线程同时首次援用此类时,可能创立多个实例,咱们平时写的最多的单例模式是懒汉式单例,即只有首次执行getInstance()时,才创立单例。例如以下代码: //javascriptvar H5SdkLog = (() => { function _module() { this.instance_id = Math.floor(Math.random()*100); } var _instance = null; return { getInstance:() => { if(!_instance){ _instance = new _module(); } return _instance; } }})();//phpclass Utils{ private static $instance; //构造方法私有化,避免内部创立实例 private function __construct(){} public static function getInstance() { if(!(self::$instance instanceof self)){ self::$instance = new self(); } return self::$instance; } //克隆办法私有化,避免复制实例 private function __clone(){}}//javapublic class SdkAppManagerUtils { private volatile static SdkAppManagerUtils instance; public static SdkAppManagerUtils getInstance() { if (instance == null) { instance = new SdkAppManagerUtils(); } return instance; }}通常来讲,PHP和JS都是单线程的,应用懒汉式单例没有啥,毕竟未必用失去这个类,推延到应用时候再生成单例的思路是正确的,合乎编程思维的。但对于java这种反对多线程的语言,就存在线程不平安,所以须要非凡解决。 ...

February 3, 2021 · 1 min · jiezi

关于设计模式:函数保险丝避免函数过热调用

前言在日常开发中,咱们会遇到很多这样的场景: 在抢购流动中,用户往往会频繁刷新接口,要给接口加上防护,频繁调用进行响应。在弱网环境中,往往会实现失败重试性能,如果失败次数多了,频繁的重试须要禁止。在股票市场中,当价格稳定的幅度在交易工夫中达到某一个限定的熔断点时,对其暂停交易一段时间的机制。......这类问题,实质是:「过热的调用」 在物理电路中,对于「过热的调用」有一种大家生存中都常见的电子元件:保险丝 保险丝会在电流异样升高到肯定的高度和热度的时候,本身熔断切断电流,爱护电路平安运行。 咱们能够模拟这样的思路,去解决编程中的「过热的调用」问题: 设定一个阈值,如果函数在短时间内调用次数达到这个阈值,就熔断一段时间。在函数有一段时间没有被调用了,让函数的热度降下来。函数保险丝的性能实现基于以上的思路,我实现了一个 npm 库:Method Fuse 应用形式如下: Step1:装置npm install @jerryc/method-fuse Step2:疾速应用import { MethodFuse } from '@jerryc/method-fuse';// 一个申请近程资源的异步函数const getAssets = async () => API.requestAssets();// 创立 MethodFuse 实例const fuse = new MethodFuse({ // 命名,用于日志输入 name: 'TestFuse', // 最大负荷,默认:3 maxLoad: 3, // 每次熔断工夫。每次熔断之后,距离 N 毫秒之后重铸,默认:5000ms breakingTime: 5000, // 主动冷却工夫。在最初一次调用距离 N 毫秒之后主动重铸,默认:1000ms coolDownTime: 1000,});// 代理原函数const getAssetsProxy = fuse.proxy(getAssets);// 高频并发调用 getAssetsProxy。getAssetsProxy();getAssetsProxy();getAssetsProxy();getAssetsProxy(); // 此次调用会熔断setTimeout(() => getAssetsProxy(), 5000); // 期待熔断重铸后,方可从新调用。// 以上会打印日志:// [method-fuse:info] TestFuse-通过保险丝(1/3)// [method-fuse:info] TestFuse-通过保险丝(2/3)// [method-fuse:info] TestFuse-通过保险丝(3/3)// [method-fuse:error] TestFuse-保险丝熔断,5000ms 之后重铸// [method-fuse:info] TestFuse-保险丝重置// [method-fuse:info] TestFuse-通过保险丝(1/3)Step3:应用装璜器如果你的我的项目中反对 TS 或者 ES Decorator,那么 MethodFuse 提供了快捷应用的装璜器。 ...

January 28, 2021 · 1 min · jiezi

关于设计模式:java中使用工厂策略模式优雅地扩展业务场景

前言最近构建公司财务计税零碎,因为我国税种较多,且不同税种的金额梯度不同,计算公式也不,并且因为业务须要,时而须要正向计算税额(税前推税后),时而须要反向计算税额(税后推税前).构建架构时,想基于一个接口,且易于扩大。遂有了应用工厂+策略模式易于扩大的想法。 策略应用前剖析(公司平安起因,我就不写具体场景了,这里以场景一,场景二,场景三...来代替)目前须要计税的有场景一/场景二/场景三。而每种场景又分为正向计算/逆向计算两种计算形式,故咱们须要应用的策略维度有: 1.场景一 + 正向计算2.场景一 + 逆向计算3.场景二 + 正向计算4.场景二 + 逆向计算5.场景三 + 正向计算6.场景四 + 逆向计算咱们能够在Spring容器启动的时候,将这几种case加载spring的时候就存在某个中央,这样咱们须要哪种场景,传递具体code,取出咱们须要的strategy就好了。那么很显著,咱们能够在工厂外面放一个hashmap用来存储具体的strategy,如下: /** * @author LiuLiang (iamcrawler@sina.com) * @since 2020-11-16 11:52 */ @Componentpublic class TaxCalculateStrategyFactory { private static Map<String, TaxCalculateStrategy> strategyMap = new ConcurrentHashMap(); /** * 获取实现策略 * * @param model * @return */ public static TaxCalculateStrategy getInvokeStrategyByModel(String model) { return strategyMap.get(model); } public static void register(String str, TaxCalculateStrategy iTaxStrategyService) { if (StringUtils.isEmpty(str) || null == iTaxStrategyService) { return; } strategyMap.put(str, iTaxStrategyService); }}有了这个工厂,咱们须要在spring容器启动的时候,就把具体strategy放到map外面,当然这个时候形式有很多种,比方在结构的时候放进去等等,当然我集体认为,此动作不应该和具体的bean有太大的耦合关系,故我应用的形式是实现spring的 InitializingBean ,并 实现本人的策略父类如下: ...

January 26, 2021 · 2 min · jiezi

关于设计模式:设计模式21-简单工厂模式怎么演变成工厂方法模式

还记得后面的简略工厂模式么?咱们开了一个水果工厂FruitFactory,生产三种水果Apple,Pear,Orange。明天给大家讲讲工厂办法模式: 老板搞水果工厂赚了点小钱,筹备扩充生产,每个工厂生产一种水果,各司其职,而不是把所有的产品类型都放到一个工厂中。 既然有多工厂,那咱们和之前一样,搞一个水果工厂类FruitFactory,把它搞成接口类。 import factory.Fruit;public interface FruitFactory { public Fruit getFruit();}水果类的定义还是一样,定义一个水果接口Fruit: public interface Fruit { public void process();}水果别离如下,我间接写到一块去了: public class Apple implements Fruit { public void process() { System.out.println("I am an Apple"); }}public class Pear implements Fruit { public void process() { System.out.println("I am a Pear"); }}public class Orange implements Fruit { public void process() { System.out.println("I am an Orange"); }}既然有多个工厂。那咱们别离定义多个工厂,对水果工厂类做不同的实现,别离生产苹果,雪梨,橙子。 public class AppleFactory implements FruitFactory { public Fruit getFruit(){ return new Apple(); }}public class PearFactory implements FruitFactory { public Fruit getFruit(){ return new Pear(); }}public class OrangeFactory implements FruitFactory { public Fruit getFruit(){ return new Orange(); }}测试代码如下: ...

January 23, 2021 · 1 min · jiezi

关于设计模式:设计模式之-外观模式

0x01:外观模式简介外观模式(又称门面模式),通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会升高应用程序的复杂度,并且进步了程序的可维护性。UML类图如下: 其中Facade是外观角色,也叫门面角色,客户端能够调用这个角色的办法,此角色通晓子系统的所有性能和责任,将客户端的申请代理给适当的子系统对象; Subsystem是子系统角色,能够同时领有一个或多个子系统,每一个子系统都不是一个独自的类,而是一个类的汇合,子系统并不知道门面的存在。 0x02:外观模式的实现定义子系统Subsystem public class SubSystemA { public void dosomethingA() { System.out.println("SubSystemA dosomethingA"); }}public class SubSystemB { public void dosomethingB() { System.out.println("SubSystemB dosomethingB"); }}外观角色Facade public class Facade { //被委托的对象 private SubSystemA a; private SubSystemB b; public Facade() { a = new SubSystemA(); b = new SubSystemB(); } //提供给内部拜访的办法 public void methodA() { this.a.dosomethingA(); } public void methodB() { this.b.dosomethingB(); }}测试代码 public class Client { public static void main(String[] args) { Facade facade = new Facade(); facade.methodA(); facade.methodB(); }}0x03:利用因为程序员薪资广泛绝对较高,所以个别有些小钱。那如何进行财产治理呢?本人购买股票呢?又不能很好的把握交易点,常常被人割韭菜。那还有什么治理财产的渠道吗?购买基金就是一个不错的渠道。 ...

January 23, 2021 · 1 min · jiezi

关于SegmentFault:设计模式第十一篇来一起瞅瞅享元模式

明天一起来看一个新的设计模式,那就是享元模式,对于此模式,常见的就是 “我的项目外包”、以及 “五子棋” 这样两个例子,咱们上面就抉择应用 “我的项目外包” 这个例子引入去讲 一 故事引入(一) 故事背景程序员小B,帮忙客户 A 做了一个展现一些产品内容的网站,通过 A 的 举荐,客户 B 、客户C 也想要做这样一个网站,然而就是模式有一些变动 有的客户心愿是新闻公布模式的有的客户心愿是博客模式的有的客户心愿是公众号模式的等等而且他们都心愿可能升高一些费用,然而每一个空间部署着一个网站,所以租借空间的费用是固定的,同时程序员小B 并不想从本人的劳动报酬中缩减费用 (二) 思考解决方案(1) 最简略的传统计划先说最简略能想到的计划,间接把网站代码复制几份,而后每一个都租借一个空间,而后对代码进行定制批改。注:这里还没思考优化或者省钱 咱们用一个 WebSite 类来模仿一个网站的模板,所有类型能够通过对 name 赋值而后调用 use 办法进行批改 public class WebSite { private String name = ""; public WebSite(String name) { this.name = name; } public void use(){ System.out.println("以后网站分类: " + name); }}如果依照方才的思路,是这样操作的 public class Test { public static void main(String[] args) { WebSite webSite1 = new WebSite("博客"); webSite1.use(); WebSite webSite2 = new WebSite("博客"); webSite2.use(); WebSite webSite3 = new WebSite("博客"); webSite3.use(); WebSite webSite4 = new WebSite("新闻公布"); webSite4.use(); WebSite webSite5 = new WebSite("公众号"); webSite5.use(); WebSite webSite6 = new WebSite("公众号"); webSite6.use(); }}运行后果: ...

January 20, 2021 · 3 min · jiezi

关于设计模式:重学设计模式一创建者模式

设计模式遵循六大准则: 繁多职责:一个类和办法只做一件事。里氏替换:多态、子类可扩大父类。依赖倒置:细节依赖形象,上层依赖下层。接口隔离:建设繁多接口。迪米特准则:起码晓得,升高耦合。开闭准则:形象架构,扩大实现。创立型模式解决的问题根本的对象创立形式可能会导致设计上存在问题,或减少设计的复杂度。创立型模式通过以某种形式管制对象的创立来解决问题。 定义创立型模式是解决对象创立的设计模式,试图依据理论状况应用适合的形式来创建对象。创立型模式旨在将零碎与其对象创立、联合、示意的形式拆散,从而让对象创立在类型、主体、形式、工夫等方面进步了零碎的灵活性。 主导思维将零碎应用的具体类封装起来。暗藏这些具体类的实例创立和联合的形式。分类对象创立模式:解决对象的创立,行将对象创立的一部分推延到另一个对象中。类创立模式:解决类的创立,行将其对象的创立推延到子类中。利用场景软件工程往往依赖于对象的组合,而不是类的继承,强调将硬编码的行为转变为定义以组根本行为来组合成简单的行为。 硬编码毛病:硬编码的行为不灵便,一旦产生设计的变更,往往须要重写或从新实现能力实现。其次,硬编码重用性不高,无奈对谬误进行跟踪。 基于以上问题,创立型模式应运而生,创建者模式使设计变得更加灵便,提供不同的形式,从代码中移除了对须要实例化的具体类的援用,加强了对象与类之间的独立思想。 在以下场景中,往往实用创立型模式: 一个零碎须要其对象和产品的创立相互独立。一组相干的对象被设计为独特应用。暗藏一个类库的具体实现,仅暴漏其接口。创立独立简单对象的不同示意。一个类心愿它的子类实现它所创立的对象。类的实例化在运行时才指定。一个类只能有一个实例,而且这个实例能在任何时候拜访到。实例应该能在不批改的状况下具备可创立型。具体实例工厂办法模式:容许一个类的实例化推延到子类中进行,即在父类中提供一个创建对象的办法,容许子类决定实例化对象的类型。形象工厂模式:提供一个创立相干或依赖对象的接口,而无需指定对象的具体类。生成器模式:将一个简单对象的创立与其示意相拆散,使同样的创立过程能够创立不同的示意,即容许分步骤创立简单对象,可能应用雷同的创立代码生成不同类型和行是的对象。原型模式:用原型实例指定要创立的对象,通过复制原型创立新的对象,即可能复制已有对象,而又无需使代码依赖其所属的类。单例模式:保障一个类只有一个实例,并提供对这个实例的全局拜访形式。参考链接重学 Java 设计模式:https://segmentfault.com/a/11...设计模式:https://refactoringguru.cn/de...

January 17, 2021 · 1 min · jiezi

关于设计模式:Head-First-设计模式-14-复合-Compound-模式

复合模式在一个解决方案中联合两个或多个模式,以解决个别或反复产生的问题。 P500 思考题public interface Quackable { public void quack();}public class MallardDuck implements Quackable { public void quack() { System.out.println("Quack"); }}public class Goose { public void honk() { System.out.println("Honk"); }}假如咱们想要在所有应用鸭子的中央应用鹅,毕竟鹅会叫、会飞、会游,和鸭子差不多。什么模式能够让咱们轻易地将鸭子和鹅掺杂在一起呢? P503 适配器模式。题目须要轻易地将一种行为转换为另一种行为,且不要扭转原有的类,所以须要应用适配器转换。思考题咱们要如何在不变动鸭子类的状况下,计算所有鸭子呱呱叫的总次数呢?有没有什么模式能够帮上忙?P505 装璜器模式。题目要求减少新的行为,且不扭转原有类,所以能够应用装璜器。代理模式。代理模式会管制拜访,而鹅经适配器后转换的行为不应该被统计,所以能够通过代理模式进行管制。思考题你可能为鹅写一个形象工厂吗?创立”内鹅外鸭“的对象时,你怎么解决? P511 新建一个工厂,专门创立被适配器转换成鸭子的鹅 public abstract class AbstractGooseDuckFactory { public abstract Quackable createGooseDuck();}public class GooseDuckFactory extends AbstractGooseDuckFactory { public Quackable createGooseDuck() { return new GooseAdapter(new Goose()); }}思考题咱们须要将鸭子视为一个汇合,甚至是子集合(subcollection),如果咱们下一次命令,就能让整个汇合的鸭子听命行事,那就太好了。什么模式能够帮咱们? P512 迭代器模式。因为咱们须要将鸭子视为一个汇合,能够遍历执行同一操作,所以能够应用迭代器模式不便遍历。组合模式。因为鸭子汇合可能会含有子集合和鸭子,并也须要反对上述行为,所以能够应用组合模式将鸭子和鸭子汇合对立起来。思考题你可能有方法继续追踪个别鸭子的实时呱呱叫吗? P516 观察者模式。题目意思就是鸭子在呱呱叫时告诉察看人员,所以鸭子是可被察看的,应该继承 Observable 类,而察看人员应该实现 Observer 接口 ,察看人员在个别鸭子上注册以便实时接管鸭子的呱呱叫行为。 依照以上设计会批改所有的鸭子类,所以就想到能够再加一个装璜器继承 Observable 类,并实现 Quackable 接口,这样改变量最小,不会扭转原有鸭子类,也能够将鸭子和可被察看解耦。但设想很美妙,一去实现就会遇到很多问题:用户代码必须与该装璜器耦合,须要特判该装璜器以执行注册观察者和告诉观察者的办法;该装璜器只能最初包装,如果被其余装璜器包装就无奈再调用相应办法;不便于将相应的办法扩大到组合模式中的汇合上。所以还是须要接口上的批改,扭转所有鸭子的行为。书上设计是让 Quackable 接口继承 QuackObservable 接口以便所有能叫的鸭子都能被察看;批改所有鸭子类,并将 Observable 类组合进鸭子类中,将注册观察者和告诉观察者的办法外部委托到 Observable 相应的办法中;同时也要批改相应的装璜器。思考题咱们还没有扭转一个 Quackable 的实现,即 QuackCounter 装璜器。它也必须成为 Observable 。你何不试着写出它的代码呢? P518 ...

January 17, 2021 · 1 min · jiezi

关于设计模式:Head-First-设计模式-13-代理-Proxy-模式

思考题如何设计一个反对近程办法调用的零碎?你要怎样才能让开发人员不必写太多代码?让近程调用看起来像本地调用一样,毫无瑕疵? P435 曾经接触过 RPC 了,所以就很容易晓得具体流程:客户端调用指标类的代理对象(消费者)的办法,消费者外部将相干调用信息通过网络传到服务端对应的指标类的代理对象(生产者)中,生产者解析调用信息,而后真正去调用指标类的理论对象,并将返回后果回传给消费者,消费者再返回给客户端。 RPC 框架应用代理模式使得外部一系列解决及信息传输等对客户端和服务端是通明的,客户端会认为理论是本地调用一样,不晓得调用了近程办法;服务端也不晓得是在给近程对象提供服务。思考题近程调用程序应该齐全通明吗?这是个好主见吗?这个办法可能会产生什么问题? P435 近程调用程序不应该齐全通明。因为引入了网络通信和数据处理(序列化、反序列化和压缩等),可能在相干过程会异样,客户端应该通晓并解决这些异样,而不应该让 RPC 框架消化掉这些异样而返回一些默认值。代理模式为另一个对象提供一个替身或占位符以管制对这个对象的拜访。 P460 特点 代理管制拜访 近程代理:管制拜访近程对象 P460虚构代理:管制拜访创立开销大的资源 P460爱护代理:基于权限管制对资源的拜访 P460动静代理:在运行时动静地创立一个代理类,并将办法的调用转发到指定的类 P474防火墙代理:管制网络资源的拜访,爱护主题免于“坏客户”的侵害。多用于防火墙零碎 P488智能援用代理:当主题被援用时,进行额定的动作,例如计一个对象被援用的次数。可用于对某些操作的日志记录 P488缓存代理:为开销大的运算后果提供临时存储;也容许多个客户共享后果,以缩小计算或网络提早。多用于 Web 服务器代理,以及内容治理与出版零碎 P488同步代理:在多线程的状况下为主题提供平安的拜访。可用于 JavaSpaces ,为分散式环境内的潜在对象汇合提供同步访问控制 P489简单暗藏代理:用来暗藏一个类的简单汇合的复杂度,并进行访问控制;有时候也成为外观代理,但与外观模式不同,因为代理管制拜访,而外观模式只提供另一组接口 P489写入时复制代理:用来管制对象的复制,办法是提早对象的复制,直到客户真的须要为止。这是虚构代理的变体。CopyOnWriteArrayList 应用这种形式 P489毛病 代理会造成设计中类的数目减少 P491代理模式和装璜器模式 P471 代理模式管制对象的拜访装璜器模式为对象减少行为代理模式和适配器模式的区别 P471 代理模式实现雷同的接口(爱护代理可能只提供给客户局部接口,与某些适配器很像)适配器模式扭转对象适配的接口思考题class ImageProxy implements Icon { // 实例变量结构器在这里 public int getIconWidth() { if (imageIcon != null) { return imageIcon.getIconWidth(); } else { return 800; } } public int getIconHeight() { if (imageIcon != null) { return imageIcon.getIconHeight(); } else { return 600; } } public void paintIcon(final Component c, Graphics g, int y, int y) { if (imageIcon != null) { imageIcon.paintIcon(c, g, x, y); } else { g.drawString("Loading CD cover, please wait...", x + 300, y + 190); // 实例化 imageIcon 获取图片 } }}以上为 CD 封面虚构代理, ImageProxy 类仿佛有两个,由条件语句管制的状态。你是否用另一个设计模式清理这样的代码?你要如何从新设计 ImageProxy ? P468 ...

January 16, 2021 · 2 min · jiezi

关于设计模式:Head-First-设计模式-12-状态-State-模式

思考题public class GumballMachine { final static int SOLD_OUT = 0; final static int NO_QUARTER = 1; final static int HAS_QUARTER = 2; final static SOLD = 3; int state = SOLD_OUT; int count = 0; public GumballMachine(int count) { this.count = count; if(count > 0) { state = NO_QUARTER; } } public void insertQuarter() { if(state == HAS_QUARTER) { // print error message } else if(state == NO_QUARTER) { state = HAS_QUARTER; // print success message } else if(state == SOLD_OUT) { // print error message } else if(state == SOLD) { // print error message } } public void ejectQuarter() { // ... } public void turnCrank() { // ... } public void dispense() { // ... }}下列哪一项形容了咱们实现的状态?(多选) P396 ...

January 15, 2021 · 2 min · jiezi

关于设计模式:Head-First-设计模式-11-组合-Composite-模式

思考题咱们不仅仅要反对多个菜单,贬值还要反对菜单中的菜单。你如何解决这个新的设计需要? P355 【提醒】在咱们的新设计中,真正须要以下三点: P354 咱们须要某种属性构造,能够包容菜单、子菜单和菜单项咱们须要确定可能在每个菜单的各个项之间游走,而且至多要像当初用迭代器一样不便咱们也须要可能更有弹性地在菜单项之间游走。比方说,可能只须要遍历甜点菜单,或者能够遍历餐厅的整个菜单(包含甜点菜单在内)提供一个接口,对立菜单和菜单项的超类 接口蕴含菜单和菜单项的独特办法,菜单中执行办法是顺次执行每个子项中的雷同办法接口蕴含菜单特有的增删改查子项的办法,菜单项中的增删改查子项的办法实现为间接抛出 UnsupportedOperationException能够通过 instanceof 判断以后项是菜单还是菜单项组合模式容许你将对象组合成树形构造来体现”整体/局部“层次结构。组合能让客户以统一的形式解决个别对象以及对象组合。 特点 把雷同的操作利用在组合和个别对象上,即能够疏忽对象组合和个别对象之间的差异 P357以违反繁多职责设计准则换取透明性,即岂但要治理层次结构,还要同时蕴含治理组合和叶节点的操作,以将组合和叶节点厚此薄彼 P367空迭代器:空对象(命令模式中提到过)的一个例子。空迭代器, hasNext() 永远返回 false , next() 永远返回 null (集体感觉能够抛出 NoSuchElementException), remove() 永远抛出 UnsupportedOperationException 。 P372 思考题public class Waitress { MenuComponent allMenus; public Waitress(MenuComponent allMenus) { this.allMenus = allMenus; } public void printMenu() { allMenus.print(); } public void printVegetarianMenu() { Iterator iterator = allMenus.createIterator(); System.out.println("\nVEGETARIAN MENU\n----"); while (iterator.hasNext()) { MenuComponent menuComponent = (MenuComponent)iterator.next(); try { if (menuComponent.isVegetarian()) { menuComponent.print(); } } catch (UnsupportedOperationException e) {} } }}printVegetarianMenu() 办法中只有菜单项的 print() 办法能够被调用,相对不能调用菜单(组合)的 print() 办法。你能说出起因吗? P373 ...

January 14, 2021 · 1 min · jiezi

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

思考题public void printMenu() { PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu(); ArrayList breakfastItems = pancakeHouseMenu.getMenuItems(); DinerMenu dinerMenu = new DinerMenu(); MenuItem[] lunchItems = dinerMenu.getMenuItems(); for (int i = 0; i < breakfastItems.size(); ++i) { MenuItem menuItem = (MenuItem) breakfastItems.get(i); System.out.print(menuItem.getName() + " "); System.out.println(menuItem.getPrice() + " "); System.out.println(menuItem.getDescription()); } for (int i = 0; i < lunchItems.length; ++i) { MenuItem menuItem = lunchItems[i]; System.out.print(menuItem.getName() + " "); System.out.println(menuItem.getPrice() + " "); System.out.println(menuItem.getDescription()); }}依据咱们的 printMenu() 实现,下列哪一项为真? P322 ...

January 13, 2021 · 2 min · jiezi

关于设计模式:Head-First-设计模式-09-模版方法-Template-Method-模式

模板办法模式在一个办法中定义一个算法的骨架,而将一些步骤提早到子类中。模板办法使得子类能够在不扭转算法构造的状况下,从新定义算法中的某些步骤。 P289 特点主导算法框架,并且爱护这个算法 P288最大化复用代码 P288算法只存在于一个中央,容易批改 P288专一算法自身,由子类提供残缺的实现 P288模板办法自身和外部具体操作解耦 P289设计准则好莱坞准则:低层组件别调用高层组件,让高层组件调用低层组件。 P296 长处避免依赖糜烂(依赖糜烂会使用户难以弄懂零碎的设计) P296思考题还有哪些模式采纳了好莱坞准则? P297 工厂办法、观察者形象工厂、外观、命令思考题咱们晓得应该多用组合,少用继承。 sort() 模板办法的实现决定不应用继承, sort 办法被实现成一个动态的办法,在运行时和 Comparable 组合。这样的做法有何优缺点?你如何处理这个难题?难道 Java 数组让这所有变得特地麻烦吗? P305 长处解耦了数组和对象,防止让对象数组继承数组毛病可排序数组的对象必须是 Comparable 的子类,比拟逻辑没法动静扭转 能够采纳 Comparator 接口,该接口承受两个待比拟的对象,返回比拟后果;并在 sort 办法加上一个 Comparator 参数难道 Java 数组让这所有变得特地麻烦吗?Java 数组不是将这所有变得麻烦的次要起因,而是 Java 数组和对象数组的没有太多的分割,不能有太多耦合,所以不应该应用继承。(如果对象数组继承 Java 数组,则要求对象自身是 Comparable 的子类,极大地限度了数组的应用场景和范畴)思考题想一想另一个模式,它是模板办法的一种非凡状况,原语操作用来创立并返回对象。这是什么模式? 工厂办法模式、形象工厂模式所思所想感觉模板办法就是在外部委托了多个策略,交给子类实现具体策略。其实平时写代码中,常常无心中会用到这种思维。比方在解决 excel 文件导入时,步骤绝对固定,先进行各种校验,而后解决 excel 文件(依据申请的不同解析成不同的对象入库),最初返回导入后果。过后我就把解决 excel 文件这步抽出来,顺便应用了一下函数式接口。public Result handleExcel(File excelFile, ExcelConsumer consumer) { // 各种校验 boolean success = consumer.consume(excelFile); // 构建后果封装对象,并返回}本文首发于公众号:满赋诸机(点击查看原文) 开源在 GitHub :reading-notes/head-first-design-patterns

January 12, 2021 · 1 min · jiezi

关于设计模式:Head-First-设计模式-08-外观-Facade-模式

思考题想想看,你在 JavaAPI 中遇到过哪些外观,你还心愿 Java 可能新增哪些外观? P262 println、log 日志接口、JDBC 接口忽然让想感觉想不进去,各种 API 都用得挺顺的,没有太麻烦的应用外观模式提供了一个对立的接口,用来拜访子系统中的一群接口。外观定义了一个高层接口,让子系统更容易应用。 P264 特点提供简化的接口的同时,仍然将零碎残缺的性能裸露进去 P260将客户从组件的子系统中解耦 P260用意是提供子系统的一个简化接口 P260区别 P270适配器模式:将一个对象包装起来以扭转其接口装璜器模式:将一个对象包装起来以减少新的行为和责任外观模式:将一群对象“包装”起来以简化其接口设计准则起码常识准则:只和你的密友谈话。即缩小对象之间的交互,缩小类的耦合。 P265 长处缩小软件的保护老本 P267毛病导致制作更多的“包装”类 P267导致减少复杂度和开发工夫 P267升高运行时的性能 P267遵循起码常识准则的方针对于任何对象,在该对象的办法内,咱们只应该调用属于以下范畴的办法: P266 该对象自身被当作办法的参数而传递进来的对象此办法所创立或实例化的任何对象对象的任何组件由前三条可知:不要调用其余办法返回后果的办法 思考题这些类有没有违反起码常识准则?请阐明起因。 P268 public class House { WeatherStation station; // 其余的办法和结构器 public float getTemp() { return station.getThermometer().getTemperature(); } // 违反了起码常识准则 // 调用了办法返回后果的办法}public class Houst { WeatherStation station; // 其余的办法和结构器 public float getTemp() { Thermometer thermometer = station.getThermometer(); return getTempHelper(thermometer); } // 没有违反起码常识准则 // 只调用了对象的组件以及对象自身的办法 public float getTempHelper(Thermometer thermometer) { return thermometer.getTemperature(); } // 只调用了参数}所思所想大部分接口性能的封装应该都算应用了外观模式。比如说下单操作,对外只裸露了一个下单接口,但外部其实有大量的子组件调用(购物车接口、运费计算接口、优惠券接口、地址接口、下单中间件、物流接口等)。再比方一个简略println,外部就蕴含了并发管制、异样捕捉、调用BufferedWriter对象进行输入管制等。本文首发于公众号:满赋诸机(点击查看原文) 开源在 GitHub :reading-notes/head-first-design-patterns

January 11, 2021 · 1 min · jiezi

关于设计模式:一天一个设计模式策略模式

蕴含角色context 策略使用者strategy 策略(行为)接口strategyImpl 策略的具体实现,通常这些实现也叫算法族场景案例demo1-佣金核算假如当初有三种业绩类型(A,B,C)须要核算佣金,通过业务剖析,三种核算过程都蕴含以下步骤: 查问元数据清空重置上一次佣金计算核算佣金判断佣金归属个别的做法是定义一个核算接口,接口中定义上述办法,而后实现核算接口,在不同的接口实现类中实现相应的细节 // 核算接口public interface ICalculate{ query(); clear(); calculate(); belong();}// A类型业绩核算public class ACalculate implements ICalculate{ // A类型具体实现 query(); clear(); calculate(); belong();}// B类型业绩核算public class BCalculate implements ICalculate{ // B类型具体实现 query(); clear(); calculate(); belong();} // 其余类型...上述写法中,存在一些问题: 如果C类型中没有 clear清空逻辑呢?能够在C类中不去实现clear()办法如果前期业务变更,不须要belong()办法了呢.新增的类型能够不做具体实现,已有的类型呢?须要一一删除belong()办法如果前期新增了逻辑呢?如:核算团队业绩,计算指标完成率须要大量改变已实现的代码因为政策变动,A,B,C采纳全新对立的 query查问,clear清空逻辑,核算和归属逻辑不同最后各种类型的业绩核算,查问清空等逻辑不同,所以实现细节全副放在了核算类中,现在许多办法能够共用,就从新定义接口,并实现query/clear新的逻辑,而后在业绩核算类中注入这些是工作中实在遇到的状况,问题不言而喻: 耦合度高: 算法的实现与算法使用者耦合代码复用低: 如果不同核算类型中用到雷同逻辑,只能复制粘贴拓展性太差: 在核算过程中新增和删除某个环节,会批改大量代码代码不足设计,档次凌乱.思考: 是否将核算过程中用到的核算环节与核算类分来到?如果办法能够共用,在核算类中能够间接注入接口实现即便不能共用,批改或新增核算环节时不须要改变核算类,代码档次更清晰了是否将这些办法形象成接口?依据核算类型的业务需要,这些办法能够有不同的实现核算的环节将不再固定,能够是任意步骤.新增核算环节只须要定义新的行为接口// 应用策略模式优化// 1. 将核算环节形象为行为接口,即核算过程有哪些行为// 2. 行为接口能够有不同的具体实现,这些实现类能够看成是一个算法族// 3. 通过组合的形式,使核算过程变动多样// 查问策略public interface Query{ query();}// 查问策略算法族public class TypeAQuery{ query(){ //typeA logic }}public class TypeBQuery{ query(){ //typeB logic }}// 清空策略public interface Clear{ clear();} '其余策略(行为) ...'// 业绩类型A的核算public class ACalculate { // 自定义核算环节,自定义核算环节具体实现 private Query query;}// 业绩类型B的核算public class BCalculate { // 自定义核算环节 private Query query; private Clear clear;}// 调用过程中,通过set()办法能够动静替换策略的实现

January 7, 2021 · 1 min · jiezi

关于设计模式:Head-First-设计模式-02-观察者-Observer-模式

思考题在咱们的一个实现中,下列哪种说法正确?(多选) P42 public class WeatherDate { // 实例变量申明 public void measurementsChanged() { float temp = getTemperature(); float humidity = getHumidity(); float pressure = getPressure(); currentConditionsDisplay.update(temp, humidity, pressure); statisticsDisplay.update(temp, humidity, pressure); forecastDisplay.update(temp, humidity, pressure); } // 其余 WeatherData 办法}[x] A. 咱们是针对具体实现编程,而非针对接口 每个布告板都是间接进行更新[x] B. 对于每个新的布告板,咱们都得批改代码 每个新的布告板,都需加一行更新代码[x] C. 咱们无奈在运行时动静地减少(或删除)布告板 没有针对接口编程,运行时无奈更改布告板[x] D. 布告板没有实现一个独特的接口 没有布告板的相干介绍,认为没有实现同一个接口起初又学到 TypeScript 和 Golang 等语言,这些语言是存在鸭子类型,不须要显示继承类或者接口(但本书所有例子都是 Java ,所以不认为是鸭子类型)【答案认为没有此选项】所有布告板都有雷同的更新形式,看起来像实现了一个独特的接口[x] E. 咱们尚未封装扭转的局部 布告板会动静更新,此处仍是针对实现编程[x] F. 咱们进犯了 WeatherData 类的封装 批改了不属于咱们负责的类【答案认为没有此选项】办法没有入参,暗示必须在办法内批改观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象扭转状态时,它的所有依赖者都会受到告诉并自动更新 P51 ...

January 5, 2021 · 1 min · jiezi

关于设计模式:设计模式

一.创立模式1.简略工厂模式:定义:不间接向客户端裸露对象创立的实现细节,而是通过一个工厂类来负责创立产品类的实例。 应用场景:无 长处:暗藏了对象创立的实现细节客户端不须要批改代码毛病:违反了繁多职责准则,将创立逻辑几种到一个工厂类里当增加新产品时,须要批改工厂类代码,违反了开闭准则from abc import abstractmethod, ABCMetaclass Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): passclass Alipay(Payment): def __init__(self, enable_yuebao=False): self.enable_yuebao = enable_yuebao def pay(self, money): if self.enable_yuebao: print("余额宝领取%s元" % money) else: print("支付宝领取%s元" % money)class ApplePay(Payment): def pay(self, money): print("苹果领取%s元" % money)class PaymentFactory: def create_payment(self, method): if method == "alipay": return Alipay() elif method == 'yuebao': return Alipay(enable_yuebao=True) elif method == "applepay": return ApplePay() else: raise NameError(method)f = PaymentFactory()p = f.create_payment("yuebao")p.pay(100)2.工厂办法模式:定义:定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。 ...

January 5, 2021 · 7 min · jiezi

关于设计模式:调用像链子责任链模式

0x01:责任链模式简介在责任链模式中,很多对象由每一个对象对其下家的援用而连接起来造成一条链。申请在这个链上进行传递,直到链上的某一个对象决定解决此申请。收回这个申请的客户端并不知道链上的哪一个对象最终解决这个申请,这使得零碎能够在不影响客户端的状况下动静地从新组织和调配责任。责任链模式的UML类图如下: 其中,Handler是形象解决者,定义了一个解决申请的接口;ConcreteHandler是具体解决者,解决它所负责的申请,可拜访它的后继者,如果可解决该申请就解决,否则就将该申请转发给它的后继者。次要角色如下: 形象解决者(Handler):定义出一个解决申请的接口。如果须要接口能够定义出一个办法以设定和返回对下一个解决对象的援用。这个角色通常由一个抽象类或者接口实现。Handler类的聚合关系给出了具体子类对下一个解决对象的援用,形象办法handleRequest()标准了子类解决申请的操作。 具体解决者(ConcreteHandler):具体解决者接到申请后,能够抉择将申请解决掉,或者将申请传给下一个Handler解决。因为具体解决者持有对一个解决对象的援用,因而,如果须要具体解决者能够拜访下一个解决对象。 0x02:责任链模式实现在工作中,免不了须要进行报销。当初与报销这个业务流程来实现责任链模式。约定如下: 报销金额 0 ~ 1W 直属下属审批即可,报销级别为1; 报销金额 1W+ ~ 5W 部门经理审批即可,报销级别为2; 报销金额 5W+ 公司负责人审批,报销级别为3; Request类负责封装申请,具体内容需依据业务产生 public class Request { private int level; public Request(int level) { this.level = level; } public void setLevel(int level) { this.level = level; } public int getLevel() { return this.level; }}Response类负责封装链中返回的后果,具体内容需依据业务产生 //解决者返回的数据public class Response { private int result; public Response(int result) { this.result = result; } public int getResult() { return result; } public void setResult(int result) { this.result = result; } }形象解决者(Handler) ...

January 5, 2021 · 2 min · jiezi

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

摘要简略介绍了什么是单例模式介绍了懒汉式和饿汉式的实现剖析了单例模式呈现的场景用数据库连接池的例子演示了单例模式概念确保一个类只能有一个实例,并提供一个全局拜访点来拜访这个实例。 要点某一个类只能创立一个一个实例必须类外部自行创立这个实例必须向零碎提供这个实例,也就是提供一个全局拜访点长处保障内存中只有一个实例,减小内存开销防止对资源的多重占用设置全局拜访点,优化和共享资源的拜访毛病扩大艰难,如果要扩大除了批改原来的代码没有第二种开发路径,违反开闭准则单例模式的性能通常都写在一个类中,如果功能设计不合理,则很容易违反繁多职责准则并发测试中不好debug场景对于Java来说,单例模式的落地就是在JVM中只存在繁多实例。 须要频繁创立一些类,应用单例能够升高零碎的内存压力,缩小GC某类只要求生成一个对象的时候,比方一个班中的班长,一个人的身份证某些类创立实例时占用资源较多,或实例化耗时较长,且常常应用。某类须要频繁实例化,而创立的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。频繁拜访数据库或文件的对象。对于一些管制硬件级别的操作,或者从零碎上来讲该当是繁多管制逻辑的操作,如果有多个实例,则零碎会齐全乱套。当对象须要被共享的场合。因为单例模式只容许创立一个对象,共享该对象能够节俭内存,并放慢对象访问速度。如 Web 中的配置对象、数据库的连接池等。实现形式懒汉式 每次拜访都须要同步,会影响性能,且耗费更多的资源,这就是懒汉式的毛病 public class Lazy{ private static volatile Lazy instance; private Lazy(){} //DLC public static getInstance(){ if(instance==null){ synchronized(Lazy.class){ if(instance==null){ instance = new Lazy(); } } } return instance; }}饿汉式 public class Hungry{ private static final Hungry instance = new Hungry(); private Hungry() {} public static Hungry getInstance() { return instance; }}实例获取数据库连接池 public final class DbConnectConfig { private static ComboPooledDataSource dataSource; static { dataSource = new ComboPooledDataSource(); dataSource.setUser(JdbcPropertiesConfig.getUSERNAME()); dataSource.setPassword(JdbcPropertiesConfig.getPASSWORD()); dataSource.setJdbcUrl(JdbcPropertiesConfig.getDATABASEURL()); dataSource.setDriverClass(xxxxxxx); //初始化连接数 dataSource.setInitialPoolSize(xxx.getINITIALPOOLSIZE()); //最小连接数 dataSource.setMinPoolSize(xxx.getMINPOOLSIZE()); //最大连接数 dataSource.setMaxPoolSize(xxx.getMAXPOOLSIZE()); //最长等待时间 dataSource.setMaxStatements(xxx.getMAXSTATEMENTS()); //最大闲暇工夫,单位毫秒 dataSource.setMaxIdleTime(xxx.getMAXIDLETIME()); dataSource.setCheckoutTimeout(5000); dataSource.setUnreturnedConnectionTimeout(20); } //这里应用DLC好一点 public synchronized static final Connection getConnection() { Connection conn = null; try { conn = dataSource.getConnection(); } catch (SQLException e) { System.out.println("\r\n数据库连贯异样"); e.printStackTrace(); } return conn; }}参考[1].单例模式设置mysql数据库连接池 ...

January 5, 2021 · 1 min · jiezi

关于设计模式:Head-First-设计模式-01-策略-Strategy-模式

当波及到“保护”时,为了“复用”目标而应用继承,终局并不完满 P4 对父类代码进行批改时,影响层面可能会很大思考题利用继承来提供 Duck 的行为,这会导致下列哪些毛病?(多选) P5 [ ] A. 代码在多个子类中反复 应用继承就是为了复用代码【答案有此选项】从另一方面思考,也有这个毛病,比方:多个子类都存在雷同的实现,但又与父类的实现不同[x] B. 运行时的行为不容易扭转 编译实现后,各种行为曾经确定,无奈再持续批改(第一次看没有抉择,看完策略模式后又感觉有这个毛病)[ ] C. 咱们不能让鸭子跳舞 在父类中写 dance() 的办法即可[x] D. 很难晓得所有鸭子的全副行为 子类能够笼罩父类的办法,所以不晓得子类的具体行为[ ] E. 鸭子不能同时又飞又叫 在父类中写 flyAndQuack() 即可[x] F. 扭转会牵一发而动全身,造成其余鸭子不想要的扭转 在父类 Duck 中减少 fly() 办法,就会使得所有的子类鸭子都会飞,包含不会飞的橡皮鸭应用接口方式的优缺点 P6长处能够防止继承时的呈现有不应具备的的行为而大量笼罩在 Java8 中能够用默认办法实现和继承成果一样的代码复用毛病某一行为在子类中都具备,却有不同实现时,依然有代码反复的问题在获取到父类时,必须得先用 instanceof 判断是否实现某接口,能力转换类型应用相干办法思考题驱动扭转的因素很多。找出你的利用中须要扭转代码的起因,一一列进去 P8 咱们的顾客或用户须要别的货色,或者想要新性能我的公司决定采纳别的数据产品,又从另一家厂商买了数据,这造成数据格式不兼容重构性能优化修复BUG、平安问题设计准则取出并封装变动的局部,让其余局部不会受到影响 P9 缩小扭转代码带来的影响便于批改和裁减,更具备弹性设计准则针对接口编程,而不是针对实现编程 P11 能够在运行时动静扭转实现“针对接口编程”即“针对超类型 (supertype) 编程” P12接口既指一种“概念”,也指 Java 的 interface设计准则多用组合,少用继承 P23 组合具备弹性,能够动静扭转实现策略模式定义了算法族,别离封装起来,让它们之间能够相互替换,此模式让算法的变动独立于应用算法的客户 P24 其实没学的时候也常常凭借教训人不知;鬼不觉中应用到了策略模式,比方:不同字段的校验逻辑、不同举荐策略、不同车型匹配逻辑等等。策略模式在 Java 源码中能够说随处可见,比方 ThreadPoolExecutor 中的 RejectedExecutionHandler 就是策略,用来进行回绝新工作。能够在初始化线程池的时候能够设置相应的四种回绝策略中的一种以满足不同的须要 private volatile RejectedExecutionHandler handler; // RejectedExecutionHandler 接口定义 public interface RejectedExecutionHandler { void rejectedExecution(Runnable r, ThreadPoolExecutor executor); }刚开始看到策略模式和观察者模式的时候,感觉两者差不多(或者说是观察者模式自带策略模式)。起初有认真思考了一下, 两者的区别次要还是在应用场景上。策略模式次要是调用策略的一方想通过这个策略实现本人所须要的性能,个别每次只有一种策略;观察者模式次要是主题想告诉观察者使观察者实现本人的性能,能够存在多个不同的观察者良好的OO设计具备的个性 P32可复用可裁减可保护所思所想教训和实战的作用还是挺大的,始终在耳濡目染地影响代码格调和思考形式系统地学习相干常识,能够使本人思考更全面,从思考架构的档次进步到模式层面平时写代码时也总会想到哪些地方须要变动,并进行肯定的解决;这是个好习惯,要持续保持,但也要保障尽快开始第一步(或者边实现边设计),避免设计很久,却在实现时发现很多中央不实用的状况产生很多时候从不同方面思考问题时,失去的答案并不一样,要有辩证思维本文首发于公众号:满赋诸机(点击查看原文) 开源在 GitHub :reading-notes/head-first-design-patterns

January 4, 2021 · 1 min · jiezi

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

GitHub源码分享微信搜寻:码农StayUp主页地址:https://gozhuyinglong.github.io 源码分享:https://github.com/gozhuyinglong/blog-demos 1. 单例模式单例模式(Singleton Pattern)是一种简略的对象创立型模式。该模式保障一个类仅有一个实例,并提供一个拜访它的全局拜访点。 所以要实现单例模式,要做到以下几点: 将构造方法私有化,杜绝应用结构器创立实例。须要本身创立惟一的一个实例,并提供一个全局拜访入口2. 单例模式的几种实现对于单例模式有以下5种实现。 2.1. 懒汉式该形式是应用synchronized关键字进行加锁,保障了线程安全性。长处:在第一次调用才初始化,防止了内存节约。毛病:对获取实例办法加锁,大大降低了并发效率。 因为加了锁,对性能影响较大,不举荐应用。 public class SingletonLazy { /** * 公有实例 */ private static SingletonLazy instance; /** * 公有构造方法 */ private SingletonLazy() { } /** * 惟一公开获取实例的办法(动态工厂办法),该办法应用synchronized加锁,来保障线程安全性 * * @return */ public static synchronized SingletonLazy getInstance() { if (instance == null) { instance = new SingletonLazy(); } return instance; }}2.2 饿汉式饿汉式是利用类加载机制来防止了多线程的同步问题,所以是线程平安的。长处:未加锁,执行效率高。毛病:类加载时就初始化实例,造成内存节约。 如果对内存要求不高的状况,还是比拟举荐应用这种形式。 public class SingletonEager { /** * 公有实例,动态变量会在类加载的时候初始化,是线程平安的 */ private static final SingletonEager instance = new SingletonEager(); /** * 公有构造方法 */ private SingletonEager() { } /** * 惟一公开获取实例的办法(动态工厂办法) * * @return */ public static SingletonEager getInstance() { return instance; }}2.3 双重校验锁利用了volatile修饰符的线程可见性(被一个线程批改后,其余线程立刻可见),即保障了懒加载,又保障了高性能,所以举荐应用。 ...

December 28, 2020 · 2 min · jiezi

关于设计模式:设计模式2-简单工厂模式了解一下

[TOC] 1.简略工厂模式介绍工厂模式,比拟罕用,属于创立型模式,也就是次要是用来创建对象的。工厂模式,有三种,次要分为: 简略工厂模式工厂办法模式形象工厂模式其中,本文要讲的就是,简略工厂模式,然而简略工厂模式,并不是属于GoF讲的23种设计模式中。简略工厂模式,也叫动态工厂办法模式。简略而言,就是有一个具体的工厂类,用来生产不同类型的对象,而这些对象,都有类似的特点,它们都实现同一个接口。 什么时候应该应用工厂模式?为什么须要工厂模式呢? 工厂模式次要是用来生成不同的对象,也就是屏蔽了对象生成的时候的复杂性,应用的时候不须要晓得对象是怎么生成的,而只须要关注要生成什么对象。如果结构一个对象特地的吃力,而咱们又常常须要结构生成这个对象,那么应用工厂模式是比拟无利的。咱们都晓得,设计模式次要就是为了设计出更加简洁,易懂,不便保护,不便拓展的代码。 如果一个很简单的对象,要在多个中央构建,那么要是改变一次,咱们就须要找出所有援用的中央,逐个批改,那会很麻烦。 简略工厂模式次要有三种角色: 简略工厂:负责创立所有的实例,按照不同的类型创立不同的对象,也就是产品。形象产品接口:也就是所有产品的一个形象,个别是所有产品都须要实现的接口。具体产品:实现形象产品接口,不同的产品做不一样的实现。2.简略工厂模式举例假如当初有一个果园,用来种植各种水果,然而每一种水果种植的形式又不一样。首先,先定义一个接口Fruit: public interface Fruit { public void process();}定义三种水果Apple,Pear,Orange: public class Apple implements Fruit{ public void process() { System.out.println("I am an Apple"); }}public class Pear implements Fruit{ public void process() { System.out.println("I am a Pear"); }}public class Orange implements Fruit{ public void process() { System.out.println("I am an Orange"); }}创立一个工厂类: public class FruitFactory { public static Fruit getFruit(String name) { if ("Apple".equalsIgnoreCase(name)) { return new Apple(); } else if ("Pear".equalsIgnoreCase(name)) { return new Pear(); } else if ("Orange".equalsIgnoreCase(name)) { return new Orange(); } return null; }}测试代码如下: ...

December 26, 2020 · 1 min · jiezi

关于设计模式:设计模式12-枚举式单例有那么好用么

[TOC] 1. 单例是什么?单例模式:是一种创立型设计模式,目标是保障全局一个类只有一个实例对象,分为懒汉式和饿汉式。所谓懒汉式,相似于懒加载,须要的时候才会触发初始化实例对象。而饿汉式正好相同,我的项目启动,类加载的时候,就会创立初始化单例对象。 后面说过单例模式以及如何毁坏单例模式,咱们个别状况尽可能阻止单例模式被毁坏,于是各种序列化,反射,以及克隆的伎俩,咱们都须要思考进来,最终的代码如下: import java.io.Serializable;public class Singleton implements Serializable { private static int num = 0; // valitile禁止指令重排 private volatile static Singleton singleton; // 禁止屡次反射调用结构器 private Singleton() { synchronized (Singleton.class) { if (num == 0) { num++; } else { throw new RuntimeException("Don't use this method"); } } } public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } // 禁止序列化的时候,从新生成对象 private Object readResolve() { return singleton; }}后面提过毁坏序列化的四种形式: ...

December 26, 2020 · 3 min · jiezi

关于设计模式:设计模式11-你想如何破坏单例模式

[TOC] 1.单例是什么?单例模式:是一种创立型设计模式,目标是保障全局一个类只有一个实例对象,分为懒汉式和饿汉式。所谓懒汉式,相似于懒加载,须要的时候才会触发初始化实例对象。而饿汉式正好相同,我的项目启动,类加载的时候,就会创立初始化单例对象。 1.1 长处如果只有一个实例,那么就能够少占用系统资源,节俭内存,拜访也会绝对较快。比拟灵便。 1.2 毛病不能应用在变动的对象上,特地是不同申请会造成不同属性的对象。因为Spring自身默认实例就是单例的,所以应用的时候须要判断利用场景,要不会造成张冠李戴的景象。而往往操作援用和汇合,就更不容易查找到这种诡异的问题。例如:一些配置获取,如果前期应用须要批改其值,要么定义应用单例,前期应用深拷贝,要么不要应用单例。 既然应用单例模式,那么就得想尽一切办法,保障实例是惟一的,这也是单例模式的使命。然而代码是人写的,再完满的人也可能写出不那么完满的代码,再平安的零碎,也有可能存在破绽。既然你想保障单例,那我偏偏找出办法,创立同一个类多个不同的对象呢?这就是对单例模式的毁坏,到底有哪些形式能够毁坏单例模式呢?次要然而不限于以下几种: 没有将结构器私有化,能够间接调用。反射调用结构器实现了cloneable接口序列化与反序列化2. 毁坏单例的几种办法2.1 通过结构器创建对象一般来说,一个略微 ✔️ 的单例模式,是不能够通过new来创建对象的,这个严格意义上不属于单例模式的毁坏。然而人不是完满的,写出的程序也不可能是完满的,总会有时候忽略了,遗记了将结构器私有化,那么内部就能够间接调用到结构器,天然就能够毁坏单例模式,所以这种写法就是不胜利的单例模式。 /** * 上面是应用双重校验锁形式实现单例 */public class Singleton{ private volatile static Singleton singleton; public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; }}下面就是应用双重检察锁的形式,实现单例模式,然而遗记了写private的结构器,默认是有一个public的结构器,如果调用会怎么样呢? public static void main(String[] args) { Singleton singleton = new Singleton(); Singleton singleton1 = new Singleton(); System.out.println(singleton.hashCode()); System.out.println(singleton1.hashCode()); System.out.println(Singleton.getSingleton().hashCode()); }运行的后果如下: ...

December 26, 2020 · 6 min · jiezi

关于设计模式:设计模式1-单例模式到底几种写法

[TOC] 单例模式,是一种比较简单的设计模式,也是属于创立型模式(提供一种创建对象的模式或者形式)。 要点: 1.波及一个繁多的类,这个类来创立本人的对象(不能在其余中央重写创立办法,初始化类的时候创立或者提供公有的办法进行拜访或者创立,必须确保只有单个的对象被创立)。2.单例模式不肯定是线程不平安的。3.单例模式能够分为两种:懒汉模式(在第一次应用类的时候才创立,能够了解为类加载的时候特地懒,要用的时候才去获取,要是没有就创立,因为是单例,所以只有第一次应用的时候没有,创立后就能够始终用同一个对象),饿汉模式(在类加载的时候就曾经创立,能够了解为饿汉曾经饿得饥渴难耐,必定先把资源紧紧拽在本人手中,所以在类加载的时候就会先创立实例) 关键字: 单例:singleton实例:instance同步: synchronized饿汉模式1.公有属性第一种single是public,能够间接通过Singleton类名来拜访。 public class Singleton { // 私有化构造方法,以避免外界应用该构造方法创立新的实例 private Singleton(){ } // 默认是public,拜访能够间接通过Singleton.instance来拜访 static Singleton instance = new Singleton();}2.私有属性第二种是用private润饰singleton,那么就须要提供static 办法来拜访。 public class Singleton { private Singleton(){ } // 应用private润饰,那么就须要提供get办法供外界拜访 private static Singleton instance = new Singleton(); // static将办法归类所有,间接通过类名来拜访 public static Singleton getInstance(){ return instance;. }}3. 懒加载饿汉模式,这样的写法是没有问题的,不会有线程平安问题(类的static成员创立的时候默认是上锁的,不会同时被多个线程获取到),然而是有毛病的,因为instance的初始化是在类加载的时候就在进行的,所以类加载是由ClassLoader来实现的,那么初始化得比拟早益处是起初间接能够用,害处也就是节约了资源,要是只是个别类应用这样的办法,依赖的数据量比拟少,那么这样的办法也是一种比拟好的单例办法。 在单例模式中个别是调用getInstance()办法来触发类装载,以上的两种饿汉模式显然没有实现lazyload(集体了解是用的时候才触发类加载) 所以上面有一种饿汉模式的改进版,利用外部类实现懒加载。 这种形式Singleton类被加载了,然而instance也不肯定被初始化,要等到SingletonHolder被被动应用的时候,也就是显式调用getInstance()办法的时候,才会显式的装载SingletonHolder类,从而实例化instance。这种办法应用类装载器保障了只有一个线程可能初始化instance,那么也就保障了单例,并且实现了懒加载。 值得注意的是:动态外部类尽管保障了单例在多线程并发下的线程安全性,然而在遇到序列化对象时,默认的形式运行失去的后果就是多例的。 public class Singleton { private Singleton(){ } //外部类 private static class SingletonHolder{ private static final Singleton instance = new Singleton(); } //对外提供的不容许重写的获取办法 public static final Singleton getInstance(){ return SingletonHolder.instance; }}懒汉模式最根底的代码(线程不平安): ...

December 26, 2020 · 2 min · jiezi

关于设计模式:设计模式第十篇外观模式开着小破车的快乐

一 开着小破车的高兴不晓得大家有没有这样开或者坐过这样一辆“小破车”,他能跑,然而外部娱乐或者说一些辅助的设施简直能够忽略不计,条件尽管艰辛了一些,然而咱们还是要本人给本人发明高兴 ,夏天太热了,先给本人装置一台空调,害,其实就是一台小电扇,接着就是咱们的 360度音响体验了,其实也就是一个低音炮,来吧,最侈靡的一个设施来了,遮光板上接一个屏幕,还能连一个简略的 DVD 机器,好的吧,麻雀虽小,然而也算五脏俱全了,就像代码一样,毕竟有性能,能运行的程序就是 “好程序” 对吧哈哈哈~ (一) 小破车的辛酸上车,关上我的小电扇,关上小音响,再放好 DVD,就能够动员小破车登程了,下车的时候熄掉火,顺次关掉 DVD,音响,电扇,就能够进来了,尽管满满的典礼感,然而因为这些外接的设施都是一个一个独立的,所以不论是开启敞开,我都须要顺次对其进行操作,本人忙了一天再回来在上折腾这个,别提多懊恼了 真艳羡他人的“奢华”小轿车,上车当前,一键打火,所有配套设施主动启动,凉飕飕的空调,动感的音乐 空想着,我能不能也将我的小破车,改装成 “智能” 的模样呢? 上面咱们就用代码来看一下咱们的小破车设施革新 (二) 革新我的小破车先复现一下我那些 DVD 、音响等等原来的状态 阐明:这里只是为了演示,就在单线程环境下,简略的用了饿汉式单例,空调也就是下面说的小电扇,权且这么叫好了 /** * 空调设备 */public class AirConditioner { // 饿汉式单例 private static AirConditioner instance = new AirConditioner(); public static AirConditioner getInstance() { return instance; } public void turnOn() { System.out.println("开启空调"); } public void turnOff() { System.out.println("敞开空调"); }}这是音响 /** * 音响设备 */public class Sound { // 饿汉式单例 private static Sound instance = new Sound(); public static Sound getInstance() { return instance; } public void turnOn() { System.out.println("开启音响"); } public void turnOff() { System.out.println("敞开音响"); }}这是 DVD ...

December 20, 2020 · 2 min · jiezi

关于设计模式:设计模式

设计模式咱们常提到的设计模式源自 1994 年出版的 Design Patterns: Elements of Reusable Object-Oriented Software 一书。 书中用 C++ 形容了 23 种罕用的软件设计模式,这些模式能够分类如下: 创立型,关注对象如何创立 工厂办法 Factory Method形象工厂 Abstract Factory建造者 Builder原型 Prototype单例 Singleton结构型 适配器 Adapter桥 Bridge组合 Composite装璜器 Decorator门面 Facade享元 Flyweight代理 Proxy行为型 责任链 Chain命令 Command解释器迭代器中介者备忘录观察者 Observer状态 State策略 Strategy模版办法访问者 Visitor有些设计模式太常见,比方单例、迭代器。有些设计模式太偏,比方解释器、备忘录。本文只会讲这些模式:工厂办法、装璜器、责任链、命令、中介者、状态、策略、访问者。 注释开始之前,须要阐明的是: 有些设计模式是基于 C++/Java 的 OOP 模式而产生的,其余语言不肯定实用,或者有别的实现形式。 本文旨在理解设计模式的思维,而不在于模式。 在编码时切忌生吞活剥,明确原理,再联合本人应用的编程语言,写出 SOLID 代码才是学习设计模式的目标。 设计模式的目标不是缩小代码数量,而是用形象层将常变和绝对不常变的代码隔开,从而收敛代码改变范畴。 引入形象层则会让代码量减少。这也是很多人困惑的一点,怎么原本几行的代码用了设计模式之后增长到一百多行? 工厂办法工厂办法是指用一个办法来结构对象,而不是间接调用构造方法。如下: interface Vehicle {}class Benz implements Vehicle {}class Camry implements Vehicle {}class CarFactory { public static Vehicle create(String brand) { if ("camry".equals(brand)) { return new Camry(); } return new Benz(); }}class Main { public static void main(String[] args) { // 调用构造方法 Vehicle car = new Benz(); // 工厂办法 // camry 甚至能够通过 args 传递进来 Vehicle car2 = CarFactory.create("camry"); }}为什么应用工厂办法呢? ...

December 18, 2020 · 5 min · jiezi

关于设计模式:设计模式思维导图

设计模式思维导图 设计模式品种:创立型:工厂办法模式(Factory Method)、形象工厂模式(Abstract Factory)、建造者模式(Builder)、原型模式(Prototype)、单例模式 (Singleton) 结构型:适配器模式(Adapter)、桥接模式(bridge)、组合模式(Composite)、装璜器模式(Decorator) 门面模式(Facade)、享元模式(Flyweight)、代理模式(Proxy)行为型:解释器模式(Interpreter)、模板办法模式(Template Method)、责任链模式(Chain of Responsibility) 命令模式(Command)、迭代器模式(Iterator)、调解者模式(Mediator)、备忘录模式(Memento) 观察者模式(Observer)、状态模式(State)、策略模式(Strategy)、访问者模式(Visitor)spring中相干设计模式相干源码可参考:https://gitee.com/flytohyj/technology-learning

December 1, 2020 · 1 min · jiezi

关于设计模式:设计模式第九篇组合模式解决层级关系结构问题

阐明:此文章两个示例中,公司构造的示例思路来自于《大话设计模式》,内容以及代码通过了肯定批改,尊重且保护作者版权所有,特此申明。 一 引言在生活中经常会见到一些具备层级关系的构造,例如学生时代的【大学-学院-业余】之间的关系就是这样,同样还有例如【总公司-分公司/部门】、【书包-书】,软件开发中也是啊,【文件夹-文件】、【容器-组件】 然而其实能够发现其共性,都是大范畴包含小范畴这样的模式,例如每一个学院上面都有不同的业余,例如计算机学院下的软件工程业余,咱们能够将其称之为 “整体-局部” 的模式 如果咱们依照最简略能想到的形式,或者就是多层继承,例如 XXX大学,上面计算机学院等多个学院去继承 XXX 大学,而软件工程,计算机科学与技术等业余又去继承了计算机学院 年轻人,这好吗,这不好。 这种形式其实是依照组织的规模大小来进行划分的,但咱们从理论登程,除了其规模,咱们更偏向于展现其组成构造,例如计算机学院下有多个业余,同时对其进行肯定的保护业务,例如更新遍历等 而应用明天要讲的组合模式就能够实现咱们的想法 二 分公司不就是一部门吗这个案例的需要是这样的,一家在全国都有分销机构的大公司,想要在全国的分公司中一起应用同一套办公管理系统,例如在北京由总部,全国几大城市有分公司,还有几个省会有办事处。要求总公司的人力资源部没财务部等办公治理性能在所有分公司和办事处都须要有,该如何办? (一) 剖析首先捋一下总公司,分公司,办事处,以及各自所属几个部门的关系 依据图能够看出,北京公司总部是最高级别的,其领有两个最间接的部门,即:人力资源部和财务部,而分公司其实和这几个部门是属于同一级的,而人力资源部,财务部这两个治理性能又能够复用于分公司。办事处这个级别在上面一层,也是如此。 剖析完这个图,其实如何去做曾经有了一个简略的思路了,简略的平行治理必定是不适合的,所以咱们将其做成一个树状构造,这样保护治理起来也会十分不便 北京总公司就好比这个根节点,其上司分公司也就是这棵树的分支,像办事处就是更小的分支,无论是总公司还是分公司,亦或办事处的相干职能部门(如财务部)都没有分支了,所以也就是叶子节点 间接解说例子或者会有一些不明朗各个公司,部门之间的关系,咱们先通过演示最简略的组合模式来铺垫一下,下一个点,再来实现下面的公司例子 (二) 组合模式(1) 什么是组合模式定义:组合模式有时又叫作“整体-局部”模式,它是一种将对象组合成树状的层次结构的模式,用来示意“整体-局部”的关系,使用户对单个对象和组合对象具备统一的拜访性 (2) 结构图 (3) 简略代码Component 为组合中的树枝以及树叶对象申明公共接口 public abstract class Component { protected String name; public String getName() { return name; } public void setName(String name) { this.name = name; } // 增加部件 public abstract void add(Component component); // 删除部件 public abstract void remove(Component component); // 遍历所有子部件内容 public abstract void traverseChild();}Leaf 即示意叶节点,起没有子节点,所有 add 和 remove 办法均没有具体业务,只是抛一个异样,只单纯实现遍历办法 ...

November 30, 2020 · 3 min · jiezi

关于设计模式:设计模式第八篇喝豆浆就是装饰者模式吗

一 引言不论是学生,还是上班族,好多人压点起床出门总是常事,楼下小摊小店急匆匆的扒拉几个包子一杯豆浆就冲向了地铁或者公车,就这杯小小的豆浆,考究那可就大了,什么大豆豆浆,五谷豆浆,黑芝麻豆浆品种繁多,要是还想加点配料那可更是花样百出,喜爱甜的加点蜂蜜,喜爱吃枣的还能加几粒红枣,竟可能的满足你的须要 其实从这一个豆浆的例子就能看进去,豆浆(好几种,大豆、五谷等等)自身是一个现有的产品,而增加蜂蜜也好,红枣也好,都是属于在现有产品上减少新的性能或者丑化,这就是咱们明天要讲的装璜者模式 进一步说到技术档次上,有时候一些组件外围代码是固定的,然而想不扭转原有构造的根底上,进行肯定的动静扩大,也是用如此的形式 上面接着用一个豆浆例子的具体代码引入其写法,前面再对其实践进行论述 二 代码演示既然是豆浆,那就属于饮品,首先定义一个形象层面的饮品类 /** * 形象饮品类,被豆浆等子类继承 */public abstract class Drink { private String name; //饮品名称 private float price = 0.0f; public String getName() { return name; } public void setName(String name) { this.name = name; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } // 计算费用 public abstract float calcCost();}既然有了形象的饮品,那么豆浆类就能够呈现了,别忘了实现父类中计算饮品费用的形象办法 /** * 饮品子类:豆浆类 */public class SoyaBeanMilk extends Drink { @Override public float calcCost() { return super.getPrice(); }}而咱们有各种豆浆,例如黄豆豆浆,五谷豆浆,黑芝麻豆浆 ...

November 27, 2020 · 2 min · jiezi

关于设计模式:设计模式创建型

单例模式单例模式,顾名思义就是一个类只有一个实例。单例次要的益处就是,1:能够解决资源拜访抵触的问题。2:缩小资源节约。 单例的实现形式1:饿汉式 在类加载的时候就实力化对象,不反对提早加载。 public class HungryDemo { private AtomicInteger id = new AtomicInteger(0); public static HungryDemo instance = new HungryDemo(); private HungryDemo() { } public static HungryDemo getInstance() { return instance; } public int getId() { return id.incrementAndGet(); } public static void main(String[] args) { for (int i = 0; i < 10; i++) { new Thread(() -> { try { Thread.sleep(new Random().nextInt(10000)); } catch (InterruptedException e) { e.printStackTrace(); } HungryDemo instance = HungryDemo.getInstance(); System.out.println(instance + "==>" + instance.getId()); }).start(); } }}2:懒汉式 ...

November 27, 2020 · 3 min · jiezi

关于设计模式:设计模式行为篇

状态模式无限状态机1:状态转换较多,但每个状态的转换业务不简单的,举荐应用查表法。 通过二维数组等形式确定下一个转换的状态,并解决对应业务2:状态转换业务较简单的,举荐应用状态模式,应用独自的类来定义状态和状态业务3:业务非常简单,状态也很少,间接应用if else就能够实现,不须要适度设计 迭代器模式通过模仿游标的滑动来遍历汇合中的数据迭代器须要实现 hasNext,currentItem,next三个办法,用于滑动游标和判断是否迭代完结遍历过程中不反对元素的增加和删除操作,因为会引起未决后果 访问者模式一个或多个操作利用到一组对象上,设计的用意是解耦操作和对象自身,放弃类的职责繁多、满足开闭准则已应答代码的复杂性。举荐应用策略模式代替访问者模式。1:访问者模式应用重载实现,容易让访问者代码爆炸。2:不奇妙,不灵便,将一组操作封装在一起,减少性能时须要批改的代码太多。反对Double Dispatch的语言不须要访问者模式,间接动静执行就能够了 备忘录模式1:备份以便于复原数据2:不能毁坏封装准则3:低频率全量备份联合高频率增量备份(redis RDF和AOF) 命令模式1:将行为封装成对象进行传递2:和策略模式的区别在于,每个命令执行的是不同的业务;策略模式指同一个业务的不同实现。例如:管制电灯的开,关属于命令;是交流电还是直流电给电灯供电属于策略。 解释器模式典型的场景是编译器的语法解释。解释器是针对特定的语句进行解释,调用特定的业务代码进行执行的过程。 中介模式1:接口对象之间的交互关系,将多对多关系通过中介类转换为一对多。2:中介模式和观察者模式的区别在于,观察者关系是单向固定的,中介则能够是双向的。3:中介模式接管音讯后进行业务编排调度。4:副作用:可能会产生一个大而全的上帝类,蕴含类所有的业务代码。(是否能够用命令模式进行拆分?)

November 25, 2020 · 1 min · jiezi

关于设计模式:一文总结设计模式

前言看了很多寓教于学写设计模式的,看的有点头疼,注意力全都在故事上了,满脑子都是鸭子,餐厅之类,还有一堆和设计模式不相干的话,翻书都翻的挺累的。这里我整顿了下23种设计模式,没什么多余的话,代码演示,简略粗犷,借鉴的中央都附上了参考链接(做个优良的搬运工),没附上的是本人总结的。借鉴的例子代码,根本都做了一些精简,如果相干例子写的有什么不精确,麻烦在评论外面指出来,最好附上代码,我会尽快修改文章中的相干实例。23种设计模式,一文出现,不便大家和本人查问,也不便本人随时批改,请配合文章旁边的纲要食用。总述7种面向对象设计准则设计准则名称定 义繁多职责准则(Single Responsibility Principle, SRP)一个类只负责一个性能畛域中的相应职责开闭准则(Open-Closed Principle, OCP)软件实体应答扩大凋谢,而对批改敞开里氏代换准则(Liskov Substitution Principle, LSP)所有援用基类对象的中央可能通明地应用其子类的对象迪米特法令(Law of Demeter, LoD)一个软件实体该当尽可能少地与其余实体产生相互作用接口隔离准则(Interface Segregation Principle, ISP)应用多个专门的接口,而不应用繁多的总接口依赖倒转准则(Dependence Inversion Principle, DIP)形象不应该依赖于细节,细节应该依赖于形象合成复用准则(Composite Reuse Principle, CRP)尽量应用对象组合,而不是继承来达到复用的目标设计模式可分为创立型(Creational),结构型(Structural)和行为型(Behavioral)三种创立型模式次要用于形容如何创建对象(5种)结构型模式次要用于形容如何实现类或对象的组合(7种)行为型模式次要用于形容类或对象怎么交互以及怎么调配职责(11种)图解 准则简述1. 繁多职责准则定义:一个类只有一个引起它变动的起因。 了解:对性能进行分类,代码进行解耦,一个类只管一件事 举例:就比方一个网络申请框架大体分为:申请类,缓存类,配置类,不能把这3个混在一起,必须分为3个类去实现不同的性能。 2.开闭准则定义:一个实体(类、函数、模块等)应该对外扩大凋谢,对内批改敞开 了解:每次发生变化时,要通过新增代码来加强现有类型的行为,而不是批改原有代码。 举例:就比方在软件的生命周期内,因为产品迭代,软件降级保护等起因,须要对原有代码进行批改时,可能会给原有代码引入谬误,也可能使得咱们对整个性能不得不进行重构,并且须要对原有代码进行从新测试,这样的话,对开发周期影响很大,所以开闭准则刚好解决这个问题。 3. 里氏替换准则定义:继承必须确保超类所领有的性质在子类中依然成立。 了解:在继承类时,除了扩大一些新的性能之外,尽量不要删除或者批改对父类办法的援用,也尽量不要重载父类的办法。 举例:你看啊,就比方Object有个办法,叫equals,如果不恪守里氏代替准则,它的子类重载了equals这个办法,并且返回了个null,这个子类的下一个继承者也会返回null,那么,在不同开发人员开发时,可能思考不到这个问题,那么就可能导致程序解体。 4.迪米特法令定义:一个模块或对象应尽量少的与其余实体之间产生相互作用,使得零碎功能模块绝对独立,这样当一个模块批改时,影响的模块就会越少,扩大起来更加容易。 了解:一个对象应该对其余对象有起码的理解;一个类应该对本人须要耦合或调用的类晓得得起码,类的外部如何实现、如何简单都与调用者或者依赖者没关系,调用者或者依赖者只须要晓得他须要的办法即可,其余的一律不关怀。类与类之间的关系越亲密,耦合度越大,当一个类产生扭转时,对另一个类的影响也越大。 举例:个别在应用框架的时候,框架的开发者会抽出一个类供内部调用,而这个次要的类像是一个中介一样去调用框架外面的其余类,恰好框架外面其余类个别都是不可拜访(调用)的,这个框架就恪守了迪米特准则,其余开发人员只关怀调用的办法,并不需要关怀性能具体如何实现。 5.接口隔离准则定义:应用多个专门性能的接口,而不是应用繁多的总接口 了解:在定义接口办法时应该合理化,尽量谋求简略最小,防止接口臃肿 举例:在理论开发中,往往为了节省时间,可能会将多个性能的办法抽成一个接口,其实这设计理念不正确的,这样会使接口处于臃肿的状态,这时就须要正当的拆分接口中的办法,另外抽取成一个独立的接口,防止原有的接口臃肿导致代码了解艰难。 6.依赖倒置准则定义:细节应该依赖于形象,而形象不应该依赖于细节 了解:高层模块不依赖低层次模块的细节,不依赖具体的类,而是依赖于接口 举例:比如说咱们写一个网络框架,为了满足不同开发者的需要,即能应用高效的OkHttp框架,也能够应用原生的API。那么是如何进行切换的呢,这个时候须要面向接口编程思维了,把一些网络申请的办法封装成一个接口,而后别离创立OkHttp和原生API的接口实现类,当然也能够扩大其余网络框架的利用。 7.合成复用准则定义:尽量应用对象组合,而不是继承来达到复用的目标。 了解:它要求在软件复用时,要尽量先应用组合或者聚合等关联关系来实现,其次才思考应用继承关系来实现。 举例:相当于咱们开发软件,一个模块的结构,就像搭积木一样,通过组合的模式,实现整体的构建;当初申明式UI框架,对于这种思维比拟贯彻。 参考 https://blog.csdn.net/lovelio...https://juejin.im/post/5d8861...创立型模式单例模式饿汉模式 public class Singleton { // 只会实例化一次 private static Singleton instance = new Singleton(); // 公有构造方法,避免被实例化 private Singleton() {} public static Singleton getInstance() { return instance; }}在未应用该类的时候,也会实例化对象,会造成资源节约,除非在肯定会用到某种类的场景,否在不倡议应用。懒汉模式 ...

November 23, 2020 · 15 min · jiezi

关于设计模式:设计模式第七篇和我一起简单认识桥接模式

一 引言桥接模式了解起来也是非常简单,咱们依然从生存中的问题登程,如果一些事物的分类能够从两个或者多个维度来划分,就比方不同品牌和不同排量的汽车,他们能够有 M x N 种后果(例如:奥迪A8 2.0排量,奥迪A6 2.0排量,飞驰S350L 3.0排量,等等) 这种状况下如果抉择继承的形式,就会呈现一种多层继承的关系,子类就会十分多,同时扩大也很麻烦 像这样的例子还有很多,比方品牌和产品类型之间,或者不同色彩和字体的图形或者文字,等等 二 桥接模式引入还是老规矩,间接用理论的代码例子引入 背景:相机品牌(索尼,佳能等)和相机类型(单反,微单,卡片机等)两种维族的组合后果 咱们想要做的就是勾销他们的继承关系,而应用组合 先创立一个形象的相机品牌类/** * 相机品牌类 */public interface CameraBrand { void showInfo();}接着就是两个具体的实现类,这里举了索尼和佳能两个品牌/** * 索尼品牌 */public class Sony implements CameraBrand { @Override public void showInfo() { System.out.print("【索尼】"); }}/** * 佳能品牌 */public class Canon implements CameraBrand { @Override public void showInfo() { System.out.print("【佳能】"); }}上面再将相机产品类形象进去,为了实现组合,引入相机品牌成员,为了能让在子类中也能拜访到,我用了 protected/** * 形象相机类 */public abstract class Camera { // 将品牌组合进来 protected CameraBrand cameraBrand; public Camera(CameraBrand cameraBrand) { this.cameraBrand = cameraBrand; } public void showInfo(){ cameraBrand.showInfo(); }}上面就是两个相机的产品具体类型/** * 单反相机 */public class SlrCameras extends Camera { public SlrCameras(CameraBrand cameraBrand) { super(cameraBrand); } @Override public void showInfo() { super.showInfo(); System.out.println("单反相机"); }}/** * 卡片相机(数字相机) */public class DigitalCamera extends Camera { public DigitalCamera(CameraBrand cameraBrand) { super(cameraBrand); } @Override public void showInfo() { super.showInfo(); System.out.println("卡片相机(数字相机)"); }}测试一下 ...

November 23, 2020 · 1 min · jiezi

关于设计模式:java与设计模式

设计模式是我在实现了一个进销存零碎后开始学习的https://github.com/moocstudent/DesignPattern其中跟着网络上的一些教程跟着敲了敲代码之后为了便于了解录制了些敲代码的视频

November 20, 2020 · 1 min · jiezi

关于设计模式:面试官所认为的单例模式

单例模式是23种GOF模式中最简略,也是最经常出现的一种设计模式,也是面试官最常爱考的一种模式,为什么呢? 因为单例模式足够简略,编写一个单例模式代码几分钟就能搞定,所以设计模式中面试官通常会选取单例模式作为出题。 上面把单例模式分几个点,别离说说哪些地方面试官能考你? 单例模式的意义 通常面试官会很抽象的问你,什么是单例模式?单例模式用来解决了什么痛点?没有单例模式咱们会怎么办?单例模式他有什么毛病吗? 单例模式是最简略的设计模式之一,属于创立型模式,它提供了一种创建对象的形式,确保只有单个对象被创立。这个设计模式次要目标是想在整个零碎中只能呈现类的一个实例,即一个类只有一个对象。 单例模式的解决的痛点就是节约资源,节省时间从两个方面看: 1.因为频繁应用的对象,能够省略创建对象所破费的工夫,这对于那些重量级的对象而言,是很重要的. 2.因为不须要频繁创建对象,咱们的GC压力也加重了,而在GC中会有STW(stop the world),从这一方面也节约了GC的工夫 单例模式的毛病:简略的单例模式设计开发都比较简单,然而简单的单例模式须要思考线程平安等并发问题,引入了局部复杂度。 扩大:从你的答复中能进行哪些扩大呢?咱们谈到了GC,有可能这时候就会问你GC,STW等常识。谈毛病的时候谈到了简单的单例模式, 这个时候可能会问你让你设计一个优良的单例模式你会怎么设计,会怎么实现? 单例模式的设计 通常这里面试官会问你单例模式怎么设计,须要看重哪些方面?一般来说单例模式有哪些实现形式? 设计单例模式的时候个别须要思考几种因素: -线程平安 -提早加载 -代码平安:如避免序列化攻打,避免反射攻打(避免反射进行公有办法调用) -性能因素 一般来说,咱们去网上百度去搜大略有7,8种实现,,上面列举一下须要重点晓得的 饿汉,懒汉(线程平安,线程非平安),双重查看(DCL)(重点),外部类,以及枚举(重点), 上面比对下各个实现:扩大:咱们下面说到了各个模式的实现,这个时候很有可能会叫你手写各个模式的代码。当然也有可能会问你线程平安,代码平安等常识。 饿汉模式 饿汉模式的代码如下: public class Singleton { private static Singleton instance = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return instance; }}饿汉模式代码比较简单,对象在类中被定义为private static,通过getInstance(),通过java的classLoader机制保障了单例对象惟一。 扩大: 有可能会问instance什么时候被初始化? Singleton类被加载的时候就会被初始化,java虚拟机标准尽管没有强制性束缚在什么时候开始类加载过程,然而对于类的初始化,虚拟机标准则严格规定了有且只有四种状况必须立刻对类进行初始化,遇到new、getStatic、putStatic或invokeStatic这4条字节码指令时,如果类没有进行过初始化,则须要先触发其初始化。 生成这4条指令最常见的java代码场景是:1)应用new关键字实例化对象2)读取一个类的动态字段(被final润饰、已在编译期把后果放在常量池的动态字段除外)3)设置一个类的动态字段(被final润饰、已在编译期把后果放在常量池的动态字段除外)4)调用一个类的静态方法 class的生命周期? class的生命周期一般来说会经验加载、连贯、初始化、应用、和卸载五个阶段 class的加载机制 这里能够聊下classloader的双亲委派模型。 双重查看DCL public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } } synchronized同步块外面可能保障只创立一个对象。然而通过在synchronized的里面减少一层判断,就能够在对象一经创立当前,不再进入synchronized同步块。这种计划不仅减小了锁的粒度,保障了线程平安,性能方面也失去了大幅晋升。 ...

November 20, 2020 · 1 min · jiezi

关于设计模式:术篇设计模式-设计模式概述及其原则

一、引言来设计模式代表了最佳的实际,通常被有教训的面向对象的软件开发人员所采纳。设计模式是软件开发人员在软件开发过程中面临的个别问题的解决方案。这些解决方案是泛滥软件开发人员通过相当长的一段时间的试验和谬误总结进去的。设计模式次要是基于面向对象的以下准则: 面向接口编程而不是实现推崇对象组合而不是继承二、设计模式分类共分为三大类 创立型模式,共五种:工厂办法模式、形象工厂模式、单例模式、建造者模式、原型模式。结构型模式,共七种:适配器模式、装璜器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。行为型模式,共十一种:策略模式、模板办法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。除以上三大类以外还有两类,即并发型模式和线程池模式。 三、设计模式六大准则0.总准则-开闭准则对扩大凋谢,对批改关闭。在程序须要进行拓展的时候,不能去批改原有的代码,而是要扩大原有代码,实现一个热插拔的成果。即:为了使程序的扩展性好,易于保护和降级。1.繁多职责准则(Single Responsibility Principle,简称SRP )核心思想:应该有且仅有一个起因引起类的变更问题形容:如果有类Class1实现职责T1,T2,当职责T1或T2有变更须要批改时,有可能影响到该类的另外一个职责失常工作。益处:类的复杂度升高、可读性进步、可维护性进步、扩展性进步、升高了变更引起的危险。需注意:繁多职责准则提出了一个编写程序的规范,用“职责”或“变动起因”来掂量接口或类设计得是否低劣,然而“职责”和“变动起因”都是不能够度量的,因我的项目和环境而异。2.里氏替换准则(Liskov Substitution Principle,简称LSP)核心思想:在应用基类的的中央能够任意应用其子类,能保障子类完满替换基类。艰深来讲:只有父类能呈现的中央子类就能呈现。反之,父类则未必能胜任。益处:加强程序的健壮性,即便减少了子类,原有的子类还能够持续运行。需注意:如果子类不能残缺地实现父类的办法,或者父类的某些办法在子类中曾经产生“畸变”,则倡议断开父子继承关系 采纳依赖、聚合、组合等关系代替继承。3.依赖倒置准则(Dependence Inversion Principle,简称DIP)核心思想:高层模块不应该依赖底层模块,二者都该依赖其形象;形象不应该依赖细节;细节应该依赖形象;阐明:高层模块就是调用端,低层模块就是具体实现类。形象就是指接口或抽象类。细节就是实现类。艰深来讲:依赖倒置准则的实质就是通过形象(接口或抽象类)使个各类或模块的实现彼此独立,互不影响,实现模块间的松耦合。问题形容:类A间接依赖类B,如果要将类A改为依赖类C,则必须通过批改类A的代码来达成。这种场景下,类A个别是高层模块,负责简单的业务逻辑;类B和类C是低层模块,负责根本的原子操作;如果批改类A,会给程序带来不必要的危险。解决方案:将类A批改为依赖接口interface,类B和类C各自实现接口interface,类A通过接口interface间接与类B或者类C产生分割,则会大大降低批改类A的几率。益处:依赖倒置的益处在小型我的项目中很难体现进去。但在大中型我的项目中能够缩小需要变动引起的工作量。使并行开发更敌对。4.接口隔离准则(Interface Segregation Principle,简称ISP)核心思想:类间的依赖关系应该建设在最小的接口上艰深来讲:建设繁多接口,不要建设宏大臃肿的接口,尽量细化接口,接口中的办法尽量少。也就是说,咱们要为各个类建设专用的接口,而不要试图去建设一个很宏大的接口供所有依赖它的类去调用。问题形容:类A通过接口interface依赖类B,类C通过接口interface依赖类D,如果接口interface对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不须要的办法。需注意:接口尽量小,然而要有限度。对接口进行细化能够进步程序设计灵活性,然而如果过小,则会造成接口数量过多,使设计复杂化。所以肯定要适度进步内聚,缩小对外交互。使接口用起码的办法去实现最多的事件为依赖接口的类定制服务。只裸露给调用的类它须要的办法,它不须要的办法则暗藏起来。只有专一地为一个模块提供定制服务,能力建设最小的依赖关系。5.迪米特法令(Law of Demeter,简称LoD)核心思想:类间解耦。艰深来讲: 一个类对本人依赖的类晓得的越少越好。自从咱们接触编程开始,就晓得了软件编程的总的准则:低耦合,高内聚。无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,能力进步代码的复用率。低耦合的长处显而易见,然而怎么样编程能力做到低耦合呢?那正是迪米特法令要去实现的。6.凋谢关闭准则(Open Close Principle,简称OCP)核心思想:尽量通过扩大软件实体来解决需要变动,而不是通过批改已有的代码来实现变动艰深来讲: 一个软件产品在生命周期内,都会发生变化,既然变动是一个既定的事实,咱们就应该在设计的时候尽量适应这些变动,以进步我的项目的稳定性和灵活性。四、总结来繁多职责准则,实现类要职责繁多。里氏替换准则,不要毁坏继承体系。依赖倒置准则,要面向接口编程。接口隔离准则,在设计接口的时候要精简繁多。迪米特法令,要升高耦合。开闭准则是总纲,对扩大凋谢,对批改敞开。

November 19, 2020 · 1 min · jiezi

关于设计模式:设计模式观察者模式工厂模式单例模式

设计模式设计模式:是指在软件开发中,通过验证的,用于解决特定环境下、反复重现的、特定问题的解决方案咱们要留神:不要为了套用设计模式而应用设计模式,在业务遇到问题时,要自然而然想到设计模式作为一种解决方案 为什么要学设计模式设计模式曾经成为软件开发人员的规范词汇学习设计模式是集体技术能力进步的路径不必反复造轮子各种源码当中充斥着各种设计模式观察者模式定义对象间的一种一对多(变换)的依赖关系,以便当一个对象(subject)的状态产生扭转时,所有依赖于它的对象都失去告诉并且自动更新应用场景当用户订阅了某种音讯,当音讯有扭转的时候,就会告诉用户音讯状态的扭转,并且执行用户对应音讯扭转所须要的行为要点 应用面向对象的形象,observer模式使咱们能够独立的扭转指标与观察者,从而使得两者之间的依赖能够达到松耦合。指标指定发送告诉时,无需指定观察者,告诉会主动流传观察者能够决定是否须要订阅告诉,指标对象对此无所不知。推模式和拉模式推模式: 指标对象向观察者推送指标的详细信息,不论观察者是否须要,相当于计算机网络中的播送。拉模式: 指标在告诉观察者的时候只传递大量信息。如果观察者须要更具体的信息,应该是观察者本身向指标对象获取。源码#include <iostream>#include <list>#include <string>using namespace std;class Subject;class Observer{public: Observer() {} virtual ~Observer() {} virtual void update(Subject *sj) = 0; virtual void update(string content) = 0;};class Subject{public: Subject() {} virtual ~Subject() {} virtual string getcontent() = 0; virtual string getAbstractContent() = 0; void attach(Observer *ob) { observers.push_back(ob); } void detach(Observer *ob) { observers.remove(ob); } virtual void notifyObservers() { for (Observer *ob : observers) { ob->update(this); //拉模型,具体数据让观察者本人去取 } } virtual void notifyObservers(string content) { for (Observer *ob : observers) { ob->update(content); //推模型 数据是由被观察者抉择 } }private: list<Observer *> observers;};class Reader : public Observer{public: Reader(string name) : _readername(name) {} virtual ~Reader() {} virtual void update(Subject *sj) { cout << _readername << " 开始浏览整个" << sj->getcontent() << endl; } virtual void update(string content) { cout << _readername << " 开始浏览报纸简介" << endl; }private: string _readername;};class paper : public Subject{public: paper() {} virtual ~paper() {} void setcontent(string content) { this->content = content; } virtual string getcontent() { return content; } virtual string getAbstractContent() { return "摘要"; }private: string content;};int main(){ paper newpaper; newpaper.setcontent("今日头条"); Reader read1("user1"), read2("user2"); newpaper.attach(&read1); //订阅 newpaper.attach(&read2); //订阅 newpaper.notifyObservers(); return 0;}工厂模式定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化提早(目标:解耦,伎俩:虚函数)到子类。动机在软件系统中,常常面临创建对象的工作。因为需要的变换,须要创立的对象的具体类型常常变换。如何应答这种变动?如何绕过惯例的对象创立办法,提供一种"封装机制"来防止客户程序和这种"具体对象创立工作"的紧耦合。应用场景数据导出各种格局领取接口,可能对应不同的领取网关:支付宝,财付通,网银在线等等。要点总结factory method模式用于隔离对象的使用者和具体类型之间的耦合关系。面对一个常常变动的具体类型,紧耦合关系会导致软件的软弱factory method模式通过面对对象的形式,将所要创立的具体对象工作提早到子类,从而实现一种扩大的策略,较好的解决了耦合关系。factory method模式解决了单个模式的需要变动。毛病在于要求创立形式/参数雷同。代码#include <iostream>using namespace std;class ExportFileProduct{public: ExportFileProduct() {} virtual ~ExportFileProduct() {} virtual bool Export(string data) = 0;};class ExportTextProduct : public ExportFileProduct{public: ExportTextProduct() {} virtual ~ExportTextProduct(){}; virtual bool Export(string data) { cout << "导出数据[" << data << "]保留成文本的形式" << endl; return true; }};class ExportDBProduct : public ExportFileProduct{public: ExportDBProduct() {} virtual ~ExportDBProduct(){}; virtual bool Export(string data) { cout << "导出数据[" << data << "]保留成数据库的形式" << endl; return true; }};class ExportJsonProduct : public ExportFileProduct{public: ExportJsonProduct() {} virtual ~ExportJsonProduct() {} virtual bool Export(string data) { cout << "导出数据:[" << data << "]保留Json的形式" << endl; return true; }};class ExportFactory{public: ExportFactory() {} virtual ~ExportFactory() {} bool Export(int type, string data) { ExportFileProduct *product = factoryMethod(type); bool ret = false; if (product) { ret = product->Export(data); } else { cout << "没有对应的类型" << endl; } return ret; }protected: virtual ExportFileProduct *factoryMethod(int type) { ExportFileProduct *product; if (type == 1) { product = new ExportTextProduct(); } else if (type == 2) { product = new ExportDBProduct(); } else if (type == 3) { product = new ExportJsonProduct(); } return product; }};单例模式保障一个类只有一个实例,并提供一个该实例的全局拜访点动机在软件系统中,常常有这样一些非凡的类,必须确保他们在零碎中只存在一个实例,能力确保他们的逻辑正确性,以及良好的效率。绕过惯例的结构器,提供一种机制来保障一个类只有一个实例。类设计者的责任 而不是使用者的责任常见写法饿汉式单例程序开始运行时就创立单例 ...

November 17, 2020 · 4 min · jiezi

关于设计模式:设计模式第六篇来康康适配器模式

一 引言设计模式就是一种思维,一种设计形式,他能够帮忙咱们对于一些问题(不肯定是技术,如生存中的问题)的解决提供一些思路,以及问题解决方案的建模与形容 例如咱们明天要讲的适配器模式就是从解决生存问题,过渡到了技术层面的问题 现实生活中,经常会呈现两者不能兼容的一种状况,例如出国了,咱们从国内带的充电插头与外国的插孔就不匹配,再例如我去香港旅游,然而又不会讲粤语,在一些小一些的商店买货色,就须要一个会讲粤语的敌人帮我在两头翻译 换到技术层面中,咱们开发某些业务的局部组件曾经在库中存在了,然而因为过来开发组件时与以后接口标准不兼容,应用适配器模式,也就是找一个两头量,帮忙咱们适配两者,对接起来,这样就不必再开发一个新的组件了 二 代码演示例子背景是这样的,咱们当初有一台苹果手机(Lightning 接口),然而咱们当初只有一根 Type-C 的充电线,咱们须要想方法,减少一个两头的转接器,从而能达到给手机充电的成果 (一) 类适配器(继承,不罕用)(1) 演示尽管这一种不罕用,然而第二种就是在第一种根底上改良的,内容不是很多,能够急躁看完喔 首先,定义一个苹果手机类,其中有一个充电的办法(Converter 在前面有说,接着往下看) /** * 客户端类:苹果手机想充电,然而充电线的头是 Type-C 的 */public class Phone { // 充电办法 public void charging(Converter converter){ converter.TypeCToLightning(); }}接着定义的就是 Type-C 这条充电线,因为它是没方法插入苹果手机的 Lightning 接口 的,所以它就是被适配的类 /** * 被适配的类:Type-C充电线 */public class TypeCLine { public void charging(){ System.out.println("开始充电了"); }}两个不能间接分割的内容,咱们曾经定义好了,即手机和 Type-C 充电线,当初就差一个两头的适配器了,当初能够定义一个转换的接口,其中定义一个Type-C 转为 Lightning 的办法 /** * 充电器转换接口 */public interface Converter { // Type-C 转为 苹果 Lightning 接口 void TypeCToLightning();}接下来就是一个具体的实现类了,实现形象接口没什么好说的,还有一步是要害——继承充电线这个须要被适配的类,至于它的利弊咱们上面再说 ...

November 15, 2020 · 2 min · jiezi

关于设计模式:设计模式第五篇什么是原型模式浅提浅拷贝和深拷贝

一 原型模式引入原型模式作为创立型模式的最初一种,它并没有波及到很多的内容,咱们来看一下 首先举一个生存上的例子,例如咱们要出版一本书,其中有一些信息字段,例如书名价格等等 public class Book { private String name; // 姓名 private int price; // 价格 private Partner partner; // 合作伙伴 // 省略构造函数、get set、toString 等}援用类型 Partner 也很简略 public class Partner{ private String name; // 省略构造函数、get set、toString 等}(一) 间接 new书籍出版必定不能只出一本,如何大批量生产呢? 有人或者想到,像上面这样每一次都从新 new(甚至写个 for 循环),咱先不说大量 new 的效率问题,首先每次一都须要从新给新对象复制,这不就像,我每刊印一本书,就得从新写一次吗??? public class Test { public static void main(String[] args) throws CloneNotSupportedException { // 初始化一个合作伙伴类型 Partner partner = new Partner("张三"); // 带参赋值 Book bookA = new Book("现实二旬不止", 66, partner); Book bookB = new Book("现实二旬不止", 66, partner); System.out.println("A: " + bookA.toString()); System.out.println("A: " + bookA.hashCode()); System.out.println("B: " + bookB.toString()); System.out.println("B: " + bookB.hashCode()); }}有的同学还或者想到了,先把 A 创立进去,而后再赋值给 B、C ..... 等等,然而这种形式其实是传递援用而不是传值,这就好比在 C 和 B 上写着,内容详情请看 A ...

November 11, 2020 · 3 min · jiezi

关于设计模式:设计模式第四篇建造者模式也没那么难

一 引言阐明:如果想要间接浏览定义等实践内容,能够间接跳转到第二大点 在生活中有很多场景与咱们明天要说的 “建造者模式” 是十分匹配的,打个比方一台计算机是由 CPU、内存、显卡、内存、鼠标、键盘、显示器等等内容组合而成的,咱们想要一台电脑,咱们不会可能本人去做这些配件,个别都是通过通知销售公司,而后其派生产技术人员给你做好指定的配件。 先不论,谁买,谁做,谁治理的问题,咱们能够剖析失去,建造电脑的这个 “过程” 是稳固的也就是说,不论什么配置的电脑,这些配件都是必须要有的,只是具体的细节不一样,例如你的配置更好,他的差一些 然而,我作为一个买家,我并不想管这些,我只通知你,我要一台中等配置的电脑,你负责“建造”好给我就行了,这就是建造者模式比拟艰深的讲法 上面咱们通过这个计算机的例子,循序渐进的看一下: 二 通过例子循序渐进意识建造者模式首先,不管怎么建,怎么买,一个 Computer 电脑类是必须的,咱们轻易筛选三个组件来进行演示,CPU、内存、显示器,补充其 get set toString 办法 /** * 产品:电脑 */public class Computer { private String cpu; // CPU private String graphicsCard; // 内存 private String displayScreen; // 显示器 public String getCpu() { return cpu; } public void setCpu(String cpu) { this.cpu = cpu; } public String getGraphicsCard() { return graphicsCard; } public void setGraphicsCard(String graphicsCard) { this.graphicsCard = graphicsCard; } public String getDisplayScreen() { return displayScreen; } public void setDisplayScreen(String displayScreen) { this.displayScreen = displayScreen; } @Override public String toString() { return "Computer{" + "cpu='" + cpu + '\'' + ", graphicsCard='" + graphicsCard + '\'' + ", displayScreen='" + displayScreen + '\'' + '}'; }}(一) 最简略直白的形式(不好)这种办法根本能够说没什么技术含量了,间接 new + set 就行了 ...

November 9, 2020 · 3 min · jiezi

关于设计模式:开发中经常使用的5种设计模式

提到设计模式,很多人都会感觉陈词滥调,有些人感觉设计模式很有必要,有些人感觉设计模式没那么重要,那么咱们在工作中是否应该器重设计模式呢?咱们是否应该将设计模式大量利用到咱们的生产过程中呢? 如果你从未据说过设计模式,我敢打赌你肯定不是一个合格程序员。这就好比一个人说他本人是数学家,然而他连勾股定理都没听过,这怎么可能? 工厂模式 这是一个最根底的设计模式,也是最罕用的设计模式,这是一个咱们平时始终在应用,但却不晓得本人在应用的设计模式。 工厂模式故名思意就是一个加工厂,不同于事实的是,这里生产的不是衣服,皮鞋,裤子等,而是咱们面向对象编程中最重要的对象。 事实中工厂的益处咱们都晓得,不仅能够批量生产,还能够批量定制,因为有着不同的模具,它能够生产出人们须要的各种类型的产品。 软件开发中,咱们更关注的是应用对象的办法,至于对象如何创立的,咱们并不是很关怀,因而,形象工厂解决了咱们的问题。咱们只须要订制咱们须要的产品性能接口,而后让工厂依照咱们的接口,也就是实现接口生产对象即可。 通过这样的调用,咱们的产品如果有问题的话,能够随时召回,能够随时被工厂补丁修补,实现了产品的灵便扩大。 适配器模式 事实中,咱们常常给手机充电,而咱们应用的就是电源适配器,为什么叫适配器呢?因为它不仅能够给咱们本人的手机充电,也能够给他人的手机充电,甚至还能够给其它用电设施充电,因为它能够适应各种充电设施,所以叫做适配器。 软件开发中,咱们简直或者不可能来到数据库而去开发一款利用,那么抉择什么数据库是咱们最须要关怀的,因为如果抉择错了,可能前期在性能上就会呈现瓶颈,那么有没有一种方法能够让咱们在不批改代码,或者批改很少的代码状况下进行数据库的无缝切换呢?答案就是适配器模式。 咱们首先定义好适配器接口,而后让各种数据库实现咱们定义好的接口,咱们在代码中应用接口中定义的办法,这样当咱们想要切换数据库的时候,只有将该数据库实现对应接口的办法,咱们就能够实现数据库的适配,就能够无缝连贯。 观察者模式 观察者模式,又叫做告诉模式,是一种一对多的模式。事实中,当校长或者老师在台上公布一个命令的时候,播送喇叭就会将命令传播给每个学生,学生们听到命令的时候,都会有本人的反馈,校长或者老师不用向学生一个个传播,因为播送喇叭会把命令传给学生,这里播送喇叭就是一个观察者,而老师和校长就是被观察者,学生们就是被告诉对象,因而观察者模式也叫做公布订阅模式。 在软件开发中,比方咱们的产品有这样一个性能,用户下单领取胜利之后,就会发送一条短信告诉用户,如果之后心愿不仅发送短信,还须要发送邮件,还须要语音告诉,在这样的状况下,咱们就能够采纳观察者模式,咱们将领取胜利信息放入到音讯队列中,至于发短信还是发邮件,由各个业务模块订阅音讯队列本人解决。这样在订单模块外面,就不须要一个个告诉短信模块,邮件模块了。 装璜器模式 现实生活中,个别状况下一个人换了一件衣服之后,咱们仍然能够认出他,衣服就是他的装璜,阐明装璜并不影响一个人的模样,也就是不影响这个人的性能,然而通过衣着一件低档外衣,却能够晋升一个人的气质,这就是装璜的作用,而装璜器模式就是通过装璜一个对象而不扭转对象来让这个对象更弱小。 举一个软件开发中的案例,比方咱们曾经设计好一个短信发送性能,并且通过测试和线上测试这个性能是没有任何问题的,然而当初有一个新的需要,要求发送短信的时候,还能语音揭示,咱们如何可能在不影响原有的性能状况下,实现这个性能呢,这个时候咱们就能够应用装璜器,也就是给短息发送类装璜一个语音性能,让它不仅能够发送短信,此外还能够实现语音发送的性能。 策略模式 策略故名思意就是实现目标计划的汇合,简略来说就是各种办法的汇合,他们都是用来实现一件事件的。 软件开发中,一个对象对不同场景采纳不同的策略去实现同一个性能,就是策略办法,如果你据说过多态,就会发现它和多态的定义很像,不同的是多态是不同对象对同一操作的不同的解决办法,而策略模式是同一个对象对同一个操作采纳不同的策略进行解决操作。 比方,咱们有一个国庆7天游的我的项目,起始点和目的地都是从北京到莫斯科,然而能够采纳不同的策略,能够飞机,能够火车,能够自驾,同一个幻想,不同的实现形式。 淘宝首页的千人千面也是策略模式,都是显示商品,面对不同的人,显示的就是不同的商品,这就是由策略决定的。 总结 如果你足够仔细的话,软件开发中的设计模式并不是凭空产生的,它肯定是来源于生存,其实,任何常识的产生都是来源于生存,只不过咱们通过学习提炼之后,将它高于生存。 设计模式不是万能的,它并不能帮忙你解决所有问题,然而它能够帮忙你解决大部分问题,并且在编码中应用设计模式的话,你会发现,你的代码看起来会更加清晰,更加有条理。 学习设计模式,应用设计模式并不是最终的目标,咱们的最终目标是无招胜有招,当你把所有的设计模式全遗记的时候,然而在编码中却能使用它们的时候,你才算没白学设计模式。

November 8, 2020 · 1 min · jiezi

关于设计模式:抽丝剥茧调停者和门面设计模式

调停者和门面设计模式明天咱们来聊两个设计模式:调停者设计模式和门面设计模式,为什么要将他们放在一起解说,因为他们两个东东太像了,仅仅是因为作用的中央不同而产生的不同的叫法。 咱们用一个对于咱们90后最难的一个问题来动手吧。假如咱们厌倦了城市生存,想要找一个宁静的中央安家,养猪,顺便写一个猪脸辨认来分类管理这些猪(幻想中的生存)。而在做这些事件的前提,咱们必须建造一个房子和一个猪圈。 咱们来看一下咱们以前会怎么做。 盖房子须要工人,砖头,水泥等等,咱们须要一个一个分割所须要的人。但我这么聪慧当然不会这么干了,所以我找了一个人来帮我实现这些事件,于是就成为了这样的流程。 我找了一个包工头,代理商帮我去实现这些事件。这个流程就是一个残缺的门面模式。是不是感觉和代理模式有点像,帮我做事件。其实吧设计模式到最初就必由之路了,正所谓,太极剑法,学多少忘多少,最初记得的只是太极剑。 咱们回到编程畛域,咱们来看一下门面模式具体的类图实现 那接下来咱们来看一下调停者设计模式。 它和门面模式最大的区别就是门面模式是挡在外层的,而它是在所有服务两头的。咱们来看一下它的原理图。 咱们再来看一下它的类图实现 发现了没,两个模式的类图实现简直雷同,所以他们的代码实现也简直雷同。 理解了他们的原理当前,咱们来聊聊他们在理论代码中的利用。 门面模式:服务器部署时的网关,将所有的申请拦挡,具体的办法转发由网关决定 调停者模式:协调中间件,微服务中将所有的服务注册到相似于zookeeper的协调中间件中,通过中间件拜访其余服务;消息中间件,须要什么音讯通过消息中间件进行获取。 对于一些比拟老的我的项目,门面模式和调停者模式的调度核心很有可能是一个,如通过Nginx治理服务。 咱们来看一下具体的代码实现吧。 门面模式代码实现(角色组成) 子系统  class Cement{  void cement(){  System.out.println("水泥");  } }  class Worker{  void worker(){  System.out.println("工人");  } }  class Brick{  void brick(){  System.out.println("砖头");  } }门面 class Contractor{  private Cement cement = new Cement();  private Worker worker = new Worker();  private Brick brick = new Brick();   void cement(){  cement.cement();  }   void worker(){  worker.worker();  }   void brick(){  brick.brick();  } }调停者模式的代码实现和门面模式简直雷同。两者只是因为应答与不同的地位而诞生,实质雷同。 ...

November 7, 2020 · 1 min · jiezi

关于设计模式:golang-策略模式之排序算法策略

起源最近在学设计模式,这个货色学起来,总是隐隐约约,看起来懂,又不知该利用到何处,咬着牙学完了之后,筹备学习算法,写了两个简略的排序算法,忽然灵光一闪,如果我想用不必的算法去排序的时候,齐全能够用策略模式,正好学以致用 示例我先设计了一个排序接口 type sortAlgo interface { sort([]int)}而后,我写了两个算法,一个是冒泡排序,一个是简略抉择排序,都实现了这个接口 type bubbleSort struct {}func (b *bubbleSort) sort(data []int) { n := len(data) for i:=0; i<n-1; i++ { for j:=n-1; j>i; j-- { if data[j-1] > data[j] { tmp := data[j-1] data[j-1] = data[j] data[j] = tmp } } }} type simpleSelectSort struct {}func (s *simpleSelectSort) sort(data []int) { n := len(data) for i:=0; i<n; i++ { minIndex := i for j:=i+1; j<n; j++ { if data[j] < data[minIndex] { minIndex = j } } if minIndex != i { tmp := data[minIndex] data[minIndex] = data[i] data[i] = tmp } }}最初,我构建一个策略模式,能够通过设计,决定应用哪一个算法 ...

November 5, 2020 · 1 min · jiezi

关于设计模式:设计模式第三篇一篇搞定工厂模式简单工厂工厂方法模式抽象工厂模式

一 为什么要用工厂模式之前解说 Spring 的依赖注入的文章时,咱们就曾经有提到过工厂这种设计模式,咱们间接先通过一个例子来看一下到底工厂模式能用来做什么? 【万字长文】Spring框架 层层递进轻松入门 (IOC和DI) 首先,咱们简略的模仿一个对账户进行增加的操作,咱们先采纳咱们以前经常应用的形式进行模仿,而后再给出改良计划 (一) 举一个模仿 Spring IOC 的例子(1) 以前的程序首先,依照咱们惯例的形式先模仿,咱们先将一套根本流程走下来 A:Service 层/** * 账户业务层接口 */public interface AccountService { void addAccount();}/** * 账户业务层实现类 */public class AccountServiceImpl implements AccountService { private AccountDao accountDao = new AccountDaoImpl(); public void addAccount() { accountDao.addAccount(); }}B:Dao 层/** * 账户长久层接口 */public interface AccountDao { void addAccount();}/** * 账户长久层实现类 */public class AccountDaoImpl implements AccountDao { public void addAccount() { System.out.println("增加用户胜利!"); }}C:调用因为,咱们创立的Maven工程并不是一个web工程,咱们也只是为了简略模仿,所以在这里,创立了一个 Client 类,作为客户端,来测试咱们的办法 ...

November 5, 2020 · 5 min · jiezi

关于设计模式:单例模式的几种实现And反射对其的破坏

一 单例模式概述(一) 什么是单例模式单例模式属于创立型模式之一,它提供了一种创建对象的最佳形式 在软件工程中,创立型模式是解决对象创立的设计模式,试图依据理论状况应用适合的形式创建对象。根本的对象创立形式可能会导致设计上的问题,或减少设计的复杂度。创立型模式通过以某种形式管制对象的创立来解决问题。因为咱们平时尽管能够定义一个全局变量使一个对象被拜访,然而它并不能保障你屡次实例化对象,最直观的,屡次创建对象的代价就是耗费性能,导致效率会低一些。单例模式就是用来解决这些问题 顺便提一个很常见的例子:例如在 Win 系的电脑下咱们永远只能关上一个工作管理器,这样能够避免出现一些资源节约,以及多窗口显示数据不统一的问题 定义:单例模式,保障一个类仅有一个实例,并且提供一个拜访它的全局拜访点 (二) 特点① 单例类只能有一个实例对象② 单例类必须本人创立本人的惟一实例③ 单例类必须对外提供一个拜访该实例的办法(三) 优缺点以及应用场景(1) 长处提供了对惟一实例的受控拜访保障了内存中只有惟一实例,缩小了内存的开销 尤其体现在一些须要屡次创立销毁实例的状况下防止对资源的多重占用 比方对文件的写操作(2) 毛病单例模式中没有形象层,没有接口,不能继承,扩大艰难,扩大须要批改原来的代码,违反了 “开闭准则”单例类的代码个别写在同一个类中,肯定水平上职责过重,违反了 “繁多职责准则”(3) 利用场景先说几个大家常见单例的例子: Windows 下的工作管理器和回收站,都是典型的单例模式,你能够试一下,没法同时关上两个的哈数据库连接池的设计个别也是单例模式,因为频繁的关上敞开与数据库的连贯,会有不小的效率损耗 然而滥用单例也可能带来一些问题,例如导致共享连接池对象的程序过多而呈现连接池溢出网站计数器,通过单例解决同步问题操作系统的文件系统Web 利用的配置对象读取,因为配置文件属于共享的资源程序的日志利用,个别也是单例,否则追加内容时,容易出问题所以,依据一些常见的例子,简略总结一下,什么时候用单例模式呢? ① 须要频繁创立销毁实例的② 实例创立时,耗费资源过多,或者耗时较多的,例如数据连贯或者IO③ 某个类只要求生成一个类的状况,例如生成惟一序列号,或者人的身份证④ 对象须要共享的状况,如 Web 中配置对象二 实现单例模式依据单例模式的定义和特点,咱们能够分为三步来实现最根本的单例模式 ① 构造函数私有化② 在类的外部创立实例③ 提供本类实例的惟一全局拜访点,即提供获取惟一实例的办法(一) 饿汉式咱们就依照最根本的这三点来写 public class Hungry { // 结构器公有,静止内部new private Hungry(){} // 在类的外部创立本人的实例 private static Hungry hungry = new Hungry(); // 获取本类实例的惟一全局拜访点 public static Hungry getHungry(){ return hungry; }}这种做法一开始就间接创立这个实例,咱们也称为饿汉式单例,然而如果这个实例始终没有被调用,会造成内存的节约,显然这样做是不适合的 (二) 懒汉式饿汉式的次要问题在于,一开始就创立实例导致的内存节约问题,那么咱们将创建对象的步骤,挪到具体应用的时候 ...

November 2, 2020 · 5 min · jiezi

关于设计模式:抽丝剥茧策略设计模式

策略设计模式哈喽,兄弟们好。明天咱们来聊一下策略设计模式。 兄弟们有没有写过这样的代码呢? if(){ }else if(){ }else if(){ }else if(){ }else if(){ }else{ }这样的代码往往在业务中的体现是:依据用户不同的身份进行特定的解决,不过随着零碎的不断扩大,会导致代码变得越来越臃肿。所以咱们须要学习以下策略模式来解决这样的问题。 咱们来看一下策略模式做了什么? 策略模式最次要的特点是:将要执行的策略传入,体现在Java中就是传入一个接口的实现类,而后调用这个接口的办法,执行策略 咱们以下面的案例为背景进行解说:假如当初要进行不同语言的打印输出成果 传统办法:if,else判断传入的是什么语言,依据判断后果输入不同的成果 策略模式:传入不同语言要执行的打印代码。比方,如果是Java则传入一个IPrintInteface的实现作为要执行的动作。 咱们代码解释一下: public class StrategyDesgin { public static void main(String[] args) { Java java = new Java(); //将咱们须要做的行为传入 test(java); } public static void test(IPrintInterface printInterface){ printInterface.print(); }}class Java implements IPrintInterface{ @Override public void print() { System.out.println("Java输入"); }}class C implements IPrintInterface{ @Override public void print() { System.out.println("C输入"); }}class JavaScript implements IPrintInterface{ @Override public void print() { System.out.println("JavaScript输入"); }}interface IPrintInterface{ void print();}咱们后面聊过JDK1.8提供的Lambda表达式,它为咱们书写策略模式提供了非常简单的写法,咱们依然以上述的场景为例,看一下代码实现。 ...

October 31, 2020 · 1 min · jiezi

关于设计模式:设计模式第一篇概述耦合UML七大原则详细分析总结基于Java

迷茫了一周,一段时间反复的 CRUD ,着实让我有点烦闷,最近打算将这些技术栈系列的文章先临时搁置一下,开启一个新的篇章《设计模式》,毕竟后面写了不少 “文治招式” 的文章,也该晋升一下内功了 一 设计模式概述(一) 什么是设计模式设计模式,即Design Patterns,是指在软件设计中,被重复应用的一种代码设计教训。应用设计模式的目标是为了可重用代码,进步代码的可扩展性和可维护性 1995年,GoF(Gang of Four,四人组/四人帮)单干出版了《设计模式:可复用面向对象软件的根底》一书,收录了23种设计模式,从此建立了软件设计模式畛域的里程碑,【GoF设计模式】(二) 为什么学习设计模式后面咱们学习了 N 种不同的技术,然而归根结底,也只是 CRUD 与 调用之间的堆砌,或者这个创意亦或是业务很欠缺、很弱小,其中也奇妙使用了各种高效的算法,然而说白了,这也只是为了实现或者说解决某个问题而做的 还有时候,两个人同时开发一款雷同的产品,均满足了预期的需要,然而 A 的程序,不仅代码健壮性强,同时前期保护扩大更是便捷(这种感觉,咱们会在前面具体的设计模式中愈发的感觉到)而 B 的代码却是一言难尽啊 有一句话总结的十分好: 设计模式的实质是面向对象设计准则的理论使用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充沛了解也就是说,毕竟像例如Java这样面向对象的语言中,如何实现一个可保护,可保护的代码,那必然就是要升高代码耦合度,适当复用代码,而要实现这所有,就须要充沛的利用 OOP 编程的个性和思维 注:上面第二大点补充【耦合】的相干概念,若不须要跳转第三四大点【UML类图及类图间的关系】/【设计模式七大准则】 在之前我写 Spring依赖注入的时候【万字长文】 Spring框架层层递进轻松入门(0C和D),就是从传统开发,讲到了如何通过工厂模式,以及多例到单例的改良,来一步步实现解耦,有趣味的敌人能够看一下哈 二 什么是耦合?(高/低)作为一篇老手都能看懂的文章,开始就一堆 IOC AOP等专业名词扔出去,如同是不太礼貌,我得把须要铺垫的常识给大家尽量说一说,如果对这块比拟明确的大佬,间接略过就OK了 耦合,就是模块间关联的水平,每个模块之间的分割越多,也就是其耦合性越强,那么独立性也就越差了,所以咱们在软件设计中,应该尽量做到低耦合,高内聚 生存中的例子:家里有一条串灯,下面有很多灯泡,如果灯坏了,你须要将整个灯带都换掉,这就是高耦合的体现,因为灯和灯带之间是严密相连,不可分割的,然而如果灯泡能够随便装配,并不影响整个灯带,那么这就叫做低耦合 代码中的例子:来看一个多态的调用,前提是 B 继承 A,援用了很屡次 A a = new B();a.method();如果你想要把B变成C,就须要批改所有new B() 的中央为 new C() 这也就是高耦合 如果如果应用咱们明天要说的 spring框架 就能够大大的升高耦合 A a = BeanFactory().getBean(B名称);a.method();这个时候,咱们只须要将B名称改为C,同时将配置文件中的B改为C就能够了 常见的耦合有这些分类: (一) 内容耦合当一个模块间接批改或操作另一个模块的数据,或者间接转入另一个模块时,就产生了内容耦合。此时,被批改的模块齐全依赖于批改它的模块。 这种耦合性是很高的,最好防止 public class A { public int numA = 1;}public class B { public static A a = new A(); public static void method(){ a.numA += 1; } public static void main(String[] args) { method(); System.out.println(a.numA); }}(二) 公共耦合两个以上的模块独特援用一个全局数据项就称为公共耦合。大量的公共耦合构造中,会让你很难确定是哪个模块给全局变量赋了一个特定的值 ...

October 26, 2020 · 6 min · jiezi

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

单例设计模式个别某些的类只须要一个就够了,反复创立他们将破费大量资源时,能够应用单例模式。比方某些工厂类、工具类。 饿汉式动态常量 /**  * @author objcfeng  * @description 饿汉式——动态常量  * @Step:   * 1.私有化结构器  * 2.创立公有类实例  * 3.私有办法返回类实例  * @date 2020/10/13  */ public class HungryMan01 {  private static final HungryMan01 instance=new HungryMan01();  private HungryMan01() {  }  public static HungryMan01 getInstance(){  return instance;  } }步骤: 私有化结构器阻止内部代码通过结构器构建类实例;创立公有类实例的成员变量申明为动态常量;通过一个私有的静态方法getInstance提供类实例。留神:提供类实例的办法肯定是动态的,不然无法访问到这个办法。 动态代码块 /**  * @author objcfeng  * @description 饿汉式——动态代码块  * @date 2020/10/13  */ public class HungryMan02 {  private static final HungryMan02 instance;  private HungryMan02() {  }  static {  instance=new HungryMan02();  }  public static HungryMan02 getInstance(){  return instance;  } }步骤差不多,只是把创立公有类实例的过程放在动态代码块中执行罢了。 ...

October 16, 2020 · 3 min · jiezi

关于设计模式:惰性模式减少重复性的浏览器特性能力检测

惰性模式:缩小每次代码执行时的重复性的分支判断,通过对对象重定义来屏蔽原对象中的分支判断。 问题代码: function on = function(dom, type, fn) { if (dom.addEventListener) { dom.addEventListener(type, fn, false); } else if (dom.attachEvent) { dom.attachEvent('on' + type, fn); } else { dom['on' + type] = fn; }}每次为元素增加事件时,都会走一遍能力检测,这是多余的,因为在同一个浏览器中两次执行办法,能力检测是不可能走两个不同的分支的。 既然第一次执行时曾经判断过了,而且当前再执行是不必要的,那么就能够在第一次执行后就从新定义它。这就是惰性模式的精华。 工作中这种模式思维有两种实现形式, 第一种就是在文件加载进来时通过闭包执行该办法对其从新定义。不过这样会使页面加载时占用肯定的资源。var on = function(dom, type, fn) { if (document.addEventListener) { return function(dom, type, fn) { dom.addEventListener(type, fn, false); } } else if (document.attachEvent) { return function(dom, type, fn) { dom.attachEvent('on' + type, fn); } } else { return function(dom, type, fn) { dom['on' + type'] = fn; } }}();第二种形式是在第一种形式寄出上做一次提早执行,在函数第一次调用的时候对其重定义。这么做的益处就是缩小文件加载时的资源耗费,然而却在第一次执行时有肯定的资源耗费。function on(dom, type, fn) { if (dom.addEventListener) { on = function(dom, type, fn) { dom.addEventListener(type, fn, false); } } else if (dom.attachEvent) { on = function(dom, type, fn) { dom.attachEvent('on' + type, fn); } } else { on = function(dom, type, fn) { dom['on' + type] = fn; } } // 执行重定义on办法 on(dom, type, fn);}第二种形式与第一种实现形式的不同之处在于,首先,外部对元素dom执行能力检测并显式重写,其次,原始函数在函数的最开端从新执行一遍来绑定事件。不过在文件加载后on办法还没能从新被定义。所以咱们还需等到某一元素绑定事件时(调用on办法时),on能力被重定义。 ...

October 10, 2020 · 1 min · jiezi

关于设计模式:代理模式

代理模式定义代理模式 是指为其余对象提供一种代理,以管制对这个对象的拜访 动态代理模式demo:大部分的房主会把房子交给中介去出租,那么这个场景就是房主是实在类,中介是代理类(帮忙房主出租房子),间接上代码 顶层接口public interface IBuyHouse { void renting(); } 房主public class Homeowner implements IBuyHouse { @Override public void renting() { System.out.println("customer: i want to buy house"); } }中介public class IntermediaryProxy implements IBuyHouse { private IBuyHouse iBuyHouse; public IntermediaryProxy(IBuyHouse iBuyHouse) { this.iBuyHouse = iBuyHouse; } @Override public void renting() { before(); iBuyHouse.renting(); after(); } private void before() { System.out.println("中介和客户沟通 ,要找一个什么样的房子"); } private void after() { System.out.println("达成协议,交定金"); } }测试public static void main(String[] args) { IBuyHouse iBuyHouse = new IntermediaryProxy(new Homeowner()); iBuyHouse.renting(); }这样就实现了一个代理类的调用接下来咱们,咱们看看如何实现动静代理 ...

September 13, 2020 · 2 min · jiezi

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

模式的定义与特点建造者(Builder)模式的定义:指将一个简单对象的结构与它的示意拆散,使同样的构建过程能够创立不同的示意,这样的设计模式被称为建造者模式。它是将一个简单的对象合成为多个简略的对象,而后一步一步构建而成。它将变与不变相拆散,即产品的组成部分是不变的,但每一部分是能够灵便抉择的。 该模式的次要长处如下: 各个具体的建造者互相独立,有利于零碎的扩大。客户端不用晓得产品外部组成的细节,便于管制细节危险。其毛病如下: 产品的组成部分必须雷同,这限度了其应用范畴。如果产品的外部变动简单,该模式会减少很多的建造者类。建造者(Builder)模式和工厂模式的关注点不同:建造者模式重视零部件的组装过程,而更重视零部件的创立过程,但两者能够联合应用。 模式的构造与实现建造者(Builder)模式由产品、形象建造者、具体建造者、指挥者等 4 个因素形成,当初咱们来剖析其根本构造和实现办法。 1. 模式的构造建造者(Builder)模式的次要角色如下。 产品角色(Product):它是蕴含多个组成部件的简单对象,由具体建造者来创立其各个滅部件。形象建造者(Builder):它是一个蕴含创立产品各个子部件的形象办法的接口,通常还蕴含一个返回简单产品的办法 getResult()。具体建造者(Concrete Builder):实现 Builder 接口,实现简单产品的各个部件的具体创立办法。指挥者(Director):它调用建造者对象中的部件结构与拆卸办法实现简单对象的创立,在指挥者中不波及具体产品的信息。其结构图如图 所示。

September 12, 2020 · 1 min · jiezi

关于设计模式:设计模式学习一

设计模式学习之 观察者模式与公布订阅模式观察者模式模式类型:行为型模式 利用场景:当一个对象被批改时,则会主动告诉依赖他的对象(概念太形象)。 对象间关系: 观察者(n) - 被观察者(1) 利用实例在A校有一个学生仪表监控零碎,而监控到学生A穿拖鞋上学零碎就会报警收回正告 阐明观察者会受被察看对象刺激,而后做出反馈。比如说猫与老鼠洞,当猫探查老鼠洞时发现了外面的老鼠时(被老鼠刺激),猫会叫并捉老鼠,当探查老鼠洞无老鼠时,猫也会走开,便无观察者与被观察者。 另外观察者别名为“订阅与公布”,例如,在微博关注了王一博,他发消息后我都能收到。 公布与订阅模式模式类型:行为型模式 利用场景:首先发布者须要公布话题,公布实现后,话题被订阅订阅者们定义,而后,对于该话题内容的批改会通过音讯发给订阅者,无订阅者时,就不会随便发送音讯。 对象间关系:发布者 (1) - 话题(n) 话题(1) - 订阅者(0-n) 利用实例在A论坛上,B同学公布了一个C话题,而后D同学对该话题感兴趣想晓得更多,于是点了关注。在前面的日子里,B同学在C话题外面公布了一个问题,而D同学在论坛音讯外面收到了C话题告诉的音讯。 事实简略例子微信公众号、QQ空间、知乎问答、掘金问答、Segmentfault答复问题的音讯等等 阐明没有了话题这个对象,那么就变为了订阅与公布模式,

September 8, 2020 · 1 min · jiezi

关于设计模式:12-设计模式组合模式

定义将对象组合成树形构造以示意“局部-整体”的层次结构。组合模式使得对单个对象和组合对象的应用具备一致性。 示例如下图所示,就是日常工作中一个很常见的树形构造的例子: 对于这种数据,咱们通常会以相似如下二维关系表的模式存储在数据库中,他们之间的树形构造关系由主外键放弃: IdNameParentId1音乐02常识03生存04迷信科普25社科人文2然而在界面渲染的时候,这种自依赖的二维表构造就显得不那么人性化了,而组合模式次要就是为了将这种数据以树形构造展现给客户端,并且使得客户端对每一个节点的操作都是一样的简略。 UML类图咱们先看看组合模式的类图: Component:组合中的对象申明接口,并实现所有类共有接口的默认行为。Leaf:叶子结点,没有子结点。Composite:枝干节点,用来存储管理子节点,如减少和删除等。从类图上能够看出,它其实就是一个一般的树的数据结构,封装的是对树节点的增删改查操作,因而,组合模式也是一种数据结构模式。 代码实现组合模式了解起来比较简单,咱们间接看看代码如何实现。 通明模式public abstract class Component{ public string Name { get; set; } public Component(string name) { this.Name = name; } public abstract int SumArticleCount(); public abstract void Add(Component component); public abstract void Remove(Component component); public abstract void Display(int depth);}public class Composite : Component{ private List<Component> _components = new List<Component>(); public Composite(string name):base(name) { } public override void Add(Component component) { _components.Add(component); } public override void Remove(Component component) { _components.Remove(component); } public override void Display(int depth) { Console.WriteLine(new string('-', depth) + Name); foreach (Component component in _components) { component.Display(depth + 1); } } public override int SumArticleCount() { int count = 0; foreach (var item in _components) { count += item.SumArticleCount(); } return count; }}public class Leaf : Component{ public Leaf(string name) : base(name) { } public override void Add(Component component) { throw new InvalidOperationException("叶子节点不能增加元素"); } public override void Remove(Component component) { throw new InvalidOperationException("叶子节点不能删除元素"); } public override int SumArticleCount() { return 1; } public override void Display(int depth) { Console.WriteLine(new string('-', depth) + Name); }}值得注意的是,因为Leaf也继承了Component,因而必须实现父类中的所有形象办法,包含Add()和Remove(),然而咱们晓得,叶子节点是不应该有这两个办法的,因而,只能给出一个空实现,或者抛出一个非法操作的异样(倡议抛出异样,这样能够明确的通知调用者不能应用,空实现会对调用者造成困扰)。对于其余业务办法,叶子节点间接返回以后叶子的信息,而枝干节点采纳递归的形式治理所有节点(其实组合模式的核心思想就是树形构造+递归)。因为叶子节点和枝干节点是继承了父类完全相同的构造,因而,客户端对整个树形构造的所有节点具备统一的操作,不必关怀具体操作的是叶子节点还是枝干节点,因而,这种模式被叫做通明模式。客户端调用代码如下: ...

September 4, 2020 · 2 min · jiezi

关于设计模式:11-设计模式桥接模式

连续上一篇装璜器模式的话题,咱们持续对需要进行降级。 示例需要还是以奶茶店为例,然而咱们不再仅仅思考奶茶的成分了,要想奶茶卖的好,还得须要一个嘹亮的品牌,奶茶有很多品牌,如一点点,COCO,喜茶等,除此之外,咱们还要对奶茶的规格进行辨别,如大杯、中杯、小杯等,不同品牌价格不同,不同规格价格也不同(不思考太简单的状况,就假如每种品牌和规格都有一个价格基数,总价间接累加)。 高级计划乍一看,跟上一篇装璜器模式中的需要没什么区别,不就是把配料换成了品牌和规格吗?咱们还是先看看继承的计划: 再看看局部实现代码: public abstract class Drink{ public string Name { get; set; } public int Price { get; set; } public abstract string Desc { get; } public abstract int Cost { get; }}public class Naicha : Drink{ public Naicha() { Name = "奶茶"; Price = 8; } public override string Desc => this.Name; public override int Cost => this.Price;}public class CoCoNaicha:Naicha{ public CoCoNaicha() { Name += "[CoCo]"; Price += 2; }}public class DaCoCoNaicha : CoCoNaicha{ public DaCoCoNaicha() { Name += "+大杯"; Price += 3; }}问题高级计划和遇到的问题也跟装璜器模式简直是截然不同的: ...

September 3, 2020 · 2 min · jiezi

关于设计模式:UML中的类图及类图之间的关系

为了后续更好的看懂类和类间接的关系这里咱们就先要理解下UML。 对立建模语言(Unified Modeling Language,UML)是用来设计软件蓝图的可视化建模语言。特点是简略、对立、图形化、能表白软件设计中的动静与动态信息。 对立建模语言能为软件开发的所有阶段提供模型化和可视化反对。而且融入了软件工程畛域的新思维、新办法和新技术,使软件设计人员沟通更扼要,进一步缩短了设计工夫,缩小开发成本。它的应用领域很宽,不仅适宜于个别零碎的开发,而且适宜于并行与分布式系统的建模。 UML 从指标零碎的不同角度登程,定义了用例图、类图、对象图、状态图、流动图、时序图、合作图、构件图、部署图等 9 种图。 这里简略介绍下设计模式种常常用到的类图,以及类之间的关系。 类、接口和类图类(Class)是指具备雷同属性、办法和关系的对象的形象,它封装了数据和行为,是面向对象程序设计(OOP)的根底,具备封装性、继承性和多态性等三大个性。在 UML 中,类应用蕴含类名、属性和操作且带有分隔线的矩形来示意。 (1) 类名(Name)是一个字符串,例如,Student。 (2) 属性(Attribute)是指类的个性,即类的成员变量。UML 按以下格局示意: [可见性]属性名:类型[=默认值]例如:-name:String 留神:“可见性”示意该属性对类外的元素是否可见,包含私有(Public)、公有(Private)、受爱护(Protected)和敌人(Friendly)4 种,在类图中别离用符号+、-、#、~示意。 (3) 操作(Operations)是类的任意一个实例对象都能够应用的行为,是类的成员办法。UML 按以下格局示意: [可见性]名称(参数列表)[:返回类型]例如:+display():void。 2.接口 接口(Interface)是一种非凡的类,它具备类的构造但不可被实例化,只能够被子类实现。它蕴含形象操作,但不蕴含属性。它形容了类或组件对外可见的动作。 3.类图 类图(ClassDiagram)是用来显示零碎中的类、接口、合作以及它们之间的动态构造和关系的一种动态模型。它次要用于形容软件系统的结构化设计,帮忙人们简化对软件系统的了解,它是系统分析与设计阶段的重要产物,也是零碎编码与测试的重要模型根据。 类图中的类能够通过某种编程 语言间接实现。类图在软件系统开发的整个生命周期都是无效的,它是面向对象零碎的建模中最常见的图。图 3 所示是“计算长方形和圆形的周长与面积”的类图,图形接口有计算面积和周长的形象办法,长方形和圆形实现这两个办法供拜访类调用。 类之间的关系在软件系统中,类不是孤立存在的,类与类之间存在各种关系。依据类与类之间的耦合度从弱到强排列,UML 中的类图有以下几种关系:依赖关系、关联关系、聚合关系、组合关系、泛化关系和实现关系。其中泛化和实现的耦合度相等,它们是最强的。 1. 依赖关系依赖(Dependency)关系是一种应用关系,它是对象之间耦合度最弱的一种关联形式,是临时性的关联。在代码中,某个类的办法通过局部变量、办法的参数或者对静态方法的调用来拜访另一个类(被依赖类)中的某些办法来实现一些职责。 在 UML 类图中,依赖关系应用带箭头的虚线来示意,箭头从应用类指向被依赖的类。 2. 关联关系关联(Association)关系是对象之间的一种援用关系,用于示意一类对象与另一类对象之间的分割,如老师和学生、徒弟和师傅、丈夫和妻子等。关联关系是类与类之间最罕用的一种关系,分为个别关联关系、聚合关系和组合关系。咱们先介绍个别关联。 关联能够是双向的,也能够是单向的。在 UML 类图中,双向的关联能够用带两个箭头或者没有箭头的实线来示意,单向的关联用带一个箭头的实线来示意,箭头从应用类指向被关联的类。也能够在关联线的两端标注角色名,代表两种不同的角色。 在代码中通常将一个类的对象作为另一个类的成员变量来实现关联关系。 3. 聚合关系聚合(Aggregation)关系是关联关系的一种,是强关联关系,是整体和局部之间的关系,是 has-a 的关系。 聚合关系也是通过成员对象来实现的,其中成员对象是整体对象的一部分,然而成员对象能够脱离整体对象而独立存在。例如,学校与老师的关系,学校蕴含老师,但如果学校停办了,老师仍然存在。 在 UML 类图中,聚合关系能够用带空心菱形的实线来示意,菱形指向整体。 4.组合关系组合(Composition)关系也是关联关系的一种,也示意类之间的整体与局部的关系,但它是一种更强烈的聚合关系,是 cxmtains-a 关系。 在组合关系中,整体对象能够管制局部对象的生命周期,一旦整体对象不存在,局部对象也将不存在,局部对象不能脱离整体对象而存在。例如,头和嘴的关系,没有了头,嘴也就不存在了。 在 UML 类图中,组合关系用带实心菱形的实线来示意,菱形指向整体。 5.泛化关系泛化(Generalization)关系是对象之间耦合度最大的一种关系,示意个别与非凡的关系,是父类与子类之间的关系,是一种继承关系,是 is-a 的关系。 ...

August 31, 2020 · 1 min · jiezi

关于设计模式:单例模式

长处提供了对惟一实例的受控拜访。因为在零碎内存中只存在一个对象,因而能够节约系统资源,对于一些须要频繁创立和销毁的对象单例模式无疑能够进步零碎的性能。容许可变数目标实例。毛病因为单例模式中没有形象层,因而单例类的扩大有很大的艰难。单例类的职责过重,在肯定水平上违反了“繁多职责准则”。滥用单例将带来一些负面问题,如为了节俭资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而呈现连接池溢出;如果实例化的对象长时间不被利用,零碎会认为是垃圾而被回收,这将导致对象状态的失落。特点构造方法公有。外部对象公有。提供返回对象的函数私有。Java中单例模式的实现形式利用公有的外部工厂类(线程平安,外部类也能够换成外部接口,不过工厂类变量的作用于要改为public)public class Singleton { private Singleton(){ System.out.println("Singleton: " + System.nanoTime()); } public static Singleton getInstance(){ return SingletonFactory.singletonInstance; } private static class SingletonFactory{ private static Singleton singletonInstance = new Singleton(); }}为什么应用动态外部类实现单例模式,能够保障线程平安?加载一个类时,其内部类不会同时被加载。一个类被加载,当且仅当其某个动态成员(动态域、结构器、静态方法等)被调用时产生。类的加载的过程是单线程执行的。它的并发平安是由JVM保障的。所以,这样写的益处是在instance初始化的过程中,由JVM的类加载机制保障了线程平安,而在初始化实现当前,不论前面多少次调用getInstance办法都不会再遇到锁的问题了。饿汉式和懒汉式饿汉式和懒汉式的区别? 在程序启动或单件模式类被加载的时候,单件模式实例就曾经被创立。 饿汉式:在程序启动或单件模式类被加载的时候,单件模式实例就曾经被创立。懒汉式:当程序第一次拜访单件模式实例时才进行创立。饿汉式(线程平安)在程序启动或单件模式类被加载的时候,单件模式实例就曾经被创立。 不让外界调用构造方法创建对象,构造方法使私有化,应用private润饰。怎么让内部获取本类的实例对象?通过本类提供一个办法,供内部调用获取实例。因为没有对象调用,所以此办法为类办法,用static润饰。通过办法返回实例对象,因为类办法(静态方法)只能调用静态方法,所以寄存该实例的变量改为类变量,用static润饰。类变量,类办法是在类加载时初始化的,只加载一次。因为内部不能创建对象,并且实例只在类加载时创立一次,饿汉式单例模式实现。public class Single2 { private static Single2 instance = new Single2(); private Single2(){ System.out.println("Single2: " + System.nanoTime()); } public static Single2 getInstance(){ return instance; }}懒汉式(如果办法没有synchronized,则线程不平安)public class Single3 { private static Single3 instance = null; private Single3(){ System.out.println("Single3: " + System.nanoTime()); } public static synchronized Single3 getInstance(){ if(instance == null){ instance = new Single3(); } return instance; }}懒汉模式改良版(线程平安,应用了double-check,即check-加锁-check,目标是为了缩小同步的开销)public class Single4 { // volatile关键字必须加,保障可见性 private volatile static Single4 instance = null; private Single4(){ System.out.println("Single4: " + System.nanoTime()); } public static Single4 getInstance(){ if(instance == null){ synchronized (Single4.class) { if(instance == null){ instance = new Single4(); } } } return instance; }}指令重排序是怎么回事?在给instance对象初始化的过程中,jvm做了上面3件事: ...

August 31, 2020 · 2 min · jiezi

关于设计模式:8-设计模式代理模式

概念界定在解说代理模式之前,咱们须要辨别一下委托、代理、中介三者的概念,因为很多人可能并不分明他们之间的区别,甚至认为没有区别。然而,如果对这三个概念没有清晰的界定,很可能会在学习的过程中一头雾水,可能会感觉代理模式跟谁都很像,跟谁都容易混同。 委托(Delegate)委托跟代理是绝对的,通常咱们说"A委托B办某事",也相当于在说"B代理A办某事",因而,委托和代理通常能够认为是等价的,这也是为什么很多时候代理模式也能够叫委托模式了,然而,在C#中,委托被赋予了新的含意,它是一种援用办法的类型,相当于C++里的函数指针。上面是委托的一个简略实现,但这只是为了阐明委托在C#中新的含意,不是本文的重点,看看就好。 public delegate int Calc(int x, int y);class Program{ static void Main(string[] args) { Calc calc = new Calc(Add); int result = calc(1, 2); Console.WriteLine(result); calc = Subtract; result = calc(1, 2); Console.WriteLine(result); } public static int Add(int x, int y) { return x + y; } public static int Subtract(int x, int y) { return x - y; }}代理(Proxy)如下图所示,代理的作用就是代替D(被代理者)实现某一件事,A、B、C拜访了代理就等同拜访了D。看似说了句废话,其实不然,这里最要害的一点就是A、B、C原本是能够拜访D的,然而因为D的懈怠,或者拜访过程比拟艰难甚至碰壁(比方线路被切断),因而才有了代理,有了代理后,A、B、C就不必再拜访D了,代理会全权处理来自A、B、C所有申请。见他如见我就是代理,如钦差大臣,产品代理商,代购,租房代理等。 中介(Mediator)如下图所示,中介是在一组简单的关系中牵线搭桥,使得A、B、C、D相互之间的交换变得简略,中介不能齐全代替A、B、C、D中的任何一方,牵线搭桥之后,被牵线的单方还是要见面的,如租房中介,婚姻中介等,婚姻中介介绍相亲的单方意识,但你不能要求婚姻中介替你谈恋爱甚至结婚生子,然而代理能够。 咱们之所以区分不清楚,是因为生存中很多时候就没辨别分明,例如,咱们很多时候认为租房中介就是租房代理,而事实并非如此,仅仅是因为很多时候一个机构同时具备了两种角色而已,简略总结一下: 委托和中介是等价的,只是主谓方向刚好产生了对调;代理能够全权代理被代理者,被代理者从头至尾都能够不必跟访问者交互,而中介只是牵线,最终被牵线的单方还是要交互的;代理通常解决的是多对一的关系,而中介解决的是多对多的关系,见他如见我是代理,牵线搭桥是中介,好好领会一下其中的区别。定义书归正传,代理模式就是为其余对象提供一种代理以管制对这个对象的拜访。 应用场景Windows快捷方式,VPN,防火墙,RPC调用,翻墙等。 ...

August 31, 2020 · 1 min · jiezi

关于设计模式:GoF的23种设计模式

GoF的23种设计模式GoF在其设计模式一书中次要介绍了23种设计模式,依据模式的实现什么工作来划分能够把设计模式分为三大类创立型模式、结构型模式和行为模式 1、创立型模式:用于形容怎么创建对象,特点“将对象的创立与应用拆散”。单例、原型、工厂办法、形象工厂、建造者等都属于创立型模式 2、结构型模式:用于形容如何将类或对象按某种布局组成更大的构造。代理、适配器、桥接、装璜、外观、享元、组合等7种为构造模式。 3、行为型模式:形容类或对象之间怎么相互协作共同完成单个对象都无奈独自实现的工作,以及怎么调配职责。模板办法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解析器等11种为行为型模式。 单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局拜访点供内部获取该实例,其拓展是无限多例模式。原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型相似的新实例。工厂办法(Factory Method)模式:定义一个用于创立产品的接口,由子类决定生产什么产品。形象工厂(AbstractFactory)模式:提供一个创立产品族的接口,其每个子类能够生产一系列相干的产品。建造者(Builder)模式:将一个简单对象分解成多个绝对简略的局部,而后依据不同须要别离创立它们,最初构建成该简单对象。代理(Proxy)模式:为某对象提供一种代理以管制对该对象的拜访。即客户端通过代理间接地拜访该对象,从而限度、加强或批改该对象的一些个性。适配器(Adapter)模式:将一个类的接口转换成客户心愿的另外一个接口,使得本来因为接口不兼容而不能一起工作的那些类能一起工作。桥接(Bridge)模式:将形象与实现拆散,使它们能够独立变动。它是用组合关系代替继承关系来实现,从而升高了形象和实现这两个可变维度的耦合度。装璜(Decorator)模式:动静的给对象减少一些职责,即减少其额定的性能。外观(Facade)模式:为多个简单的子系统提供一个统一的接口,使这些子系统更加容易被拜访。享元(Flyweight)模式:使用共享技术来无效地反对大量细粒度对象的复用。组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具备统一的拜访性。模板办法(TemplateMethod)模式:定义一个操作中的算法骨架,而将算法的一些步骤提早到子类中,使得子类能够不扭转该算法构造的状况下重定义该算法的某些特定步骤。策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们能够互相替换,且算法的扭转不会影响应用算法的客户。命令(Command)模式:将一个申请封装为一个对象,使发出请求的责任和执行申请的责任宰割开。职责链(Chain of Responsibility)模式:把申请从链中的一个对象传到下一个对象,直到申请被响应为止。通过这种形式去除对象之间的耦合。状态(State)模式:容许一个对象在其外部状态产生扭转时扭转其行为能力。观察者(Observer)模式:多个对象间存在一对多关系,当一个对象产生扭转时,把这种扭转告诉给其余多个对象,从而影响其余对象的行为。中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,升高零碎中对象间的耦合度,使原有对象之间不用相互了解。迭代器(Iterator)模式:提供一种办法来程序拜访聚合对象中的一系列数据,而不裸露聚合对象的外部示意。访问者(Visitor)模式:在不扭转汇合元素的前提下,为一个汇合中的每个元素提供多种拜访形式,即每个元素有多个访问者对象拜访。备忘录(Memento)模式:在不毁坏封装性的前提下,获取并保留一个对象的外部状态,以便当前复原它。

August 30, 2020 · 1 min · jiezi

关于设计模式:7-设计模式适配器模式

生存中的例子 如上图所示,生存中适配器无处不在,如电源适配器,读卡器,甚至多转接头读卡器等,都是很常见的例子,它们的目标都是将本来不能一起工作的部件可能在一起工作。在软件工程畛域的适配器也是同样相似的作用。 定义适配器模式是将一个类的接口转换成客户心愿的另外一个接口,行将本来因为接口不兼容而不能一起工作的那些类能够一起工作。 示例这里就以一个简略的读卡器的例子来加以阐明。通常在咱们应用SD卡存储文件时,会存在如下状况: 电脑只有USB接口,不能直接插入SD卡;电脑和SD卡都是成型的产品,不可能革新电脑或者读卡器。因而,咱们须要在两头实现一个转换器,也就是读卡器。具体关系图如下: 不难发现,电脑(Computer)和读卡器(SdReader)都实现了USB接口(IUsb),而读卡器又聚合了SD卡,也就是SD卡随时能够插到读卡器上。具体实现代码如下: public interface IUsb{ void Request();}public class Sd{ public void ReadWrite() { Console.WriteLine("存取数据"); }}public class Computer{ private IUsb _usb; public void SetUsb(IUsb usb) { _usb = usb; } public void ConnectUsb() { if (_usb != null) { _usb.Request(); } }}public class SdReader : IUsb{ private Sd _sd; public SdReader(Sd sd) { _sd = sd; } public void Request() { _sd.ReadWrite(); }}其中,USB接口(IUsb)、电脑(Computer)还有SD卡(Sd)都是不可变,而读卡器(SdReader)的目标就是为了让SD卡(Sd)可能适配USB接口(IUsb)而额定减少的局部。 ...

August 28, 2020 · 1 min · jiezi

关于设计模式:6-设计模式创建型模式总结

创立型模式就是与对象的创立无关的模式,包含简略工厂模式、工厂办法模式、形象工厂模式、单例模式、建造者模式和原型模式。 工厂模式工厂模式就是用工厂办法代替new来实例化对象的形式。次要目标是升高new所带来的耦合关系。 简略工厂工厂模式最简略的一种实现,隔离了new的过程,但不满足开闭准则,因为简略工厂模式通常采纳静态方法实现,因而也叫动态工厂,个别会配合反射一起应用。 工厂办法次要目标是将类的实例化提早到工厂类的子类中实现,即由子类来决定应该实例化哪一个类,对于客户端来说,打消了对具体产品的依赖。 形象工厂有了产品族概念,为互相关联或者相互依赖的对象提供一个对立的接口。 单例模式解决的是实体对象个数的问题,即应答对象只须要创立一次的状况,当然,创立固定个数的状况也是能够的,当初更风行的形式是通过IOC容器实现。 建造者模式次要用于动静的创立简单的、具备复合属性的对象。从构造上能够看成是一个形象工厂(生产相关联的部件)和一个简略工厂(组装残缺的产品)的组合应用。建造者能够形象并束缚产品的建造流程。 原型模式用于反复创立一个蕴含大量公共属性,或者初始化须要耗费大量资源的对象时,即次要用于实现对象的自我复制。 尽量将实现原型模式的类标记为sealed;尽量避免应用ICloneable接口。更多内容,欢送关注公众号:

August 27, 2020 · 1 min · jiezi

关于设计模式:5-设计模式原型模式

定义原型模式是用原型实例指定创建对象的品种,并通过拷贝这些原型创立新的对象。简略地说就是,首先创立一个实例,而后通过这个实例去拷贝(克隆)创立新的实例。 需要咱们还是通过一个简略需要开始说起,通常状况下,找工作时,须要筹备多份简历,简历信息大致相同,然而能够依据不同的公司的岗位需要微调工作经验细节,以及薪资要求,例如有的公司要求电商教训优先,那么就能够把电商相干的工作细节多写一点,而有的要求治理教训,那么工作细节就须要更多的体现治理能力,薪资要求也会依据具体情况填写具体数值或者面议等。 咱们先抛开原型模式不谈,咱们能够考虑一下,后面讲到的几个创立型模式是否满足需要呢? 首先,咱们须要多份简历,单例模式间接就能够Pass掉了,其次,因为简历信息比较复杂,起码也有几十个字段,并且依据不同状况,可能会产生局部批改,因而,三个工厂模式也不能满足需要。不过想到这里,咱们想到建造者模式或者满足需要,因为它就是用来创立简单对象的,无妨先用建造者模式试一下。 先定义简历: public abstract class ResumeBase{ /// <summary> /// 姓名 /// </summary> public string Name { get; set; } /// <summary> /// 性别 /// </summary> public string Gender { get; set; } /// <summary> /// 年龄 /// </summary> public int Age { get; set; } /// <summary> /// 冀望薪资 /// </summary> public string ExpectedSalary { get; set; } public abstract void Display();}/// <summary>/// 工作经验/// </summary>public class WorkExperence{ public string Company { get; set; } public string Detail { get; set; } public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } public void Display() { Console.WriteLine("工作经验:"); Console.WriteLine($"{this.Company}\t{this.StartDate.ToShortDateString()}-{EndDate.ToShortDateString()}"); Console.WriteLine("工作具体:"); Console.WriteLine(this.Detail); }}public class ItResume : ResumeBase{ /// <summary> /// 工作经验 /// </summary> public WorkExperence WorkExperence { get; set; } public override void Display() { Console.WriteLine($"姓名:\t{this.Name}"); Console.WriteLine($"性别:\t{this.Gender}"); Console.WriteLine($"年龄:\t{this.Age}"); Console.WriteLine($"冀望薪资:\t{this.ExpectedSalary}"); Console.WriteLine("--------------------------------"); if (this.WorkExperence != null) { this.WorkExperence.Display(); } Console.WriteLine("--------------------------------"); }}再定义建造者: ...

August 26, 2020 · 3 min · jiezi

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

角色建造者故名思维,就是建房子的人,是来自建筑工程畛域的的概念,其中蕴含三种次要角色: 建造者(Builder):不同品种的工人,如打地基的,建房梁的,室内装修的等;具体的建造者(ConcreteBuilder):每个工种对应的具体的工人;指挥者(Director):工程队总指挥,包工头,指挥具体的建造者建房子;具体产品(Product):最终建成的房子。定义建造者模式是将一个简单的对象的构建与它的示意拆散,使得同样的构建过程能够创立不同的示意。创建者模式暗藏了简单对象的创立过程,它把简单对象的创立过程加以形象,通过子类继承或者重载的形式,动静的创立简单的、具备复合属性的对象。 案例上面将通过一个小案例来解释阐明什么建造者模式。 简化需要假如须要制作一个手机,手机包含CPU,内存,屏幕等几个局部,而CPU,内存,屏幕配置不同又有高端,低端之分。要求手机配置能够灵便搭配。 初始版UML 该版本间接在在须要的时候通过new创立不同规格的CPU,内存,屏幕等对象。 长处简略,并且配置可灵便搭配 毛病面向了实现编程,用户须要晓得太多的创立细节工厂办法革新基于上述起因,咱们通过工厂办法革新,屏蔽具体配件的创立细节。 长处屏蔽了配件的发明细节配置可灵便搭配毛病复杂度急剧增大,类爆炸把配件的组装交给手机类(Phone)解决不合理没有屏蔽手机发明细节形象工厂+简略工厂革新为了解决类爆炸的问题,咱们合并配件工厂类,由一个形象工厂创立相干配件,再由简略工厂组装生产手机成品。 简化UML(规范版本)因为无论是CPU、内存还是屏幕都属于手机的一部分,因而整个产品还是手机自身,由此,可简化上述UML图,并形象失去下图: 长处肯定水平上,打消了类爆炸问题职责拆散,由独自一个生产线组装手机毛病配件配置变得固定了,不能随便组合对大多数场景仍然过于简单,比方,未必每一个配置的手机都须要一个生产线,组装手机也未必须要一个独自的生产线。进一步简化很多场景中并没有指挥者,或者说指挥者就是建造者自身,因而,建造者模式可进一步简化为如下构造: 再进一步革新同样的,大多数状况一个建造者只会有一个实现子类,因而,还可用进一步简化,这样能够应用委托对须要建造的对象进行灵便的配置。 简化UML(简化版本,最罕用) 长处简略,灵便,代码优雅 毛病用户应用老本绝对较高,须要使用者本人配置外部参数。 总结建造者模式通常用于动静的创立简单的、具备复合属性的对象。在.Net Core也存在大量的建造者模式的应用,例如,StringBuilder、HostBuilder、IHostBuilder、IWebHostBuilder、ConfigurationBuilder等,有趣味的能够学习下。 源码链接视频分享链接更多内容请关注公众号:

August 24, 2020 · 1 min · jiezi

关于设计模式:面向对象的七大设计原则与设计模式

1. 设计主旨可维护性和可复用性 1.1. 可维护性(Maintainability)如果要思考到软件的可维护性, 从设计之初就要思考软件的可扩展性 灵活性 可插拔性 等等;1.2. 可复用性(Reuseability)复用不仅仅是代码的复用: 代码的复用 算法的复用 数据结构的复用要做到这两点, 在设计的时候, 就必须遵循一些准则, 咱们称之为面向对象的设计准则 2. 设计准则 SOLIDCD设计准则一览:(注: 这个缩写是我本人的记忆简写) S => SRP=Single Responsibility Principle = 繁多职责准则O => OCP=Open Close Principle = 开闭准则L => LSP= Liscov Substitution Principle = 里氏代换准则I => ISP = Interface Segregation Principle = 接口隔离准则D => DIP = Dependency Inversion Principle = 依赖倒转准则C => CARP = Composite/Aggregation Reuse Principle = 合成/聚合复用准则D => Lod=Law of Demeter = 迪米特法令1. 繁多职责准则Single Responsibility Principle ...

August 24, 2020 · 2 min · jiezi

关于设计模式:jdk中的设计模式策略模式RejectedExecutionHandler

1. 策略模式提供一组算法/策略, 调用时遵循DIP准则, 调用形象的策略接口, 实现类可自定义, 新增策略, 只须要新增扩大, 调用者能够抉择自在切换 juc中线程池 TPE(ThreadPoolExecutor)的回绝策略就是用了策略模式: 拒绝执行处理器 在TPE(ThreadPoolExecutor类中提供的4个策略实现): 2. 线程池的回绝策略RejectedExecutionHandler 2.1 AbortPolicy: 抛出异样AbortPolicy // 抛出异样: RejectedExecutionException (拒绝执行异样) /** * A handler for rejected tasks that throws a RejectedExecutionException. */public static class AbortPolicy implements RejectedExecutionHandler { /** * Creates an {@code AbortPolicy}. */ public AbortPolicy() { } /** * Always throws RejectedExecutionException. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task * @throws RejectedExecutionException always */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); }}2.2. CallerRunsPolicy: 调用者代解决/** * A handler for rejected tasks that runs the rejected task directly in the calling thread of the execute method, * unless the executor has been shut down, in which case the task is discarded. */public static class CallerRunsPolicy implements RejectedExecutionHandler { /** * Creates a {@code CallerRunsPolicy}. */ public CallerRunsPolicy() { } /** * Executes task r in the caller's thread, unless the executor * has been shut down, in which case the task is discarded. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } }}2.3. DiscardPolicy: 默默抛弃静默抛弃被回绝的工作/** * A handler for rejected tasks that silently discards the rejected task. */public static class DiscardPolicy implements RejectedExecutionHandler { /** * Creates a {@code DiscardPolicy}. */ public DiscardPolicy() { } /** * Does nothing, which has the effect of discarding task r. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { }}2.4. DiscardOldestPolicy: 抛弃最早的未解决工作抛弃最早的未解决申请,而后重试执行. 若executor曾经被敞开,在这种状况下,该工作也被抛弃。/** * A handler for rejected tasks that discards the oldest unhandled request and then retries execute, * unless the executor is shut down, in which case the task is discarded. */public static class DiscardOldestPolicy implements RejectedExecutionHandler { /** * Creates a {@code DiscardOldestPolicy} for the given executor. */ public DiscardOldestPolicy() { } /** * Obtains and ignores the next task that the executor * would otherwise execute, if one is immediately available, * and then retries execution of task r, unless the executor * is shut down, in which case task r is instead discarded. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } }}

August 24, 2020 · 2 min · jiezi

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

定义单例模式,属于创立类型的一种罕用的设计模式。它的目标就是为了创立的类在以后过程中只有一个实例。 目标从定义能够看出,应用单例模式的目标无非就是上面两个: 全局惟一全局共享长处确保全局共享同一个实例节约系统资源实现伎俩1. 动态类这种形式不是单例模式,但能够满足需要,在正式生产中也会常常用到。 代码public static class SingletonSample1 { private static int _counter = 0; public static int IncreaseCount() { return ++_counter; }}留神:这里的++_counter其实存在高并发问题,严格上应该用Interlocked.Increment(ref _counter)的形式,因为咱们次要讲的是单例模式并且简略且能演示成果,所以成心疏忽了这一点。下同 长处应用起来不便,简略毛病动态类不能继承类,也不能实现接口,不能通过接口或者形象办法(虚办法)实现多态;动态类必须在第一次加载时初始化,如果我的项目中用不到会导致资源节约;2. 单例模式一这是最简略的一种单例模式,也是比拟罕用的一种形式,可在正式生产中应用。 代码public sealed class SingletonSample2 { private static readonly SingletonSample2 _instance = new SingletonSample2(); private int _counter = 0; private SingletonSample2() { } public static SingletonSample2 Instance { get { return _instance; } } public int IncreaseCount() { return ++_counter; }}长处解决了动态类不能继承类,不能实现接口,不能通过接口或者形象办法(虚办法)实现多态的问题;毛病没有解决第一次加载时初始化,资源节约的问题。以上两种形式都存在第一次加载时,资源节约的问题,但在内存资源越来越便宜的明天,通常这种节约是能够承受的,因而也不用过于纠结这种节约。当然,在条件容许的状况下,能优化还是要优化的。 ...

August 24, 2020 · 2 min · jiezi

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

工厂顾名思义就是创立产品,实质就是用工厂办法代替new操作创立一种实例化对象的形式。依据不同的实现形式和形象级别又可分为简略工厂,工厂办法和形象工厂三种模式。 案例需要封装一个SqlHelper类,实现对SqlServer的操作,且后续可能须要同时反对SqlServer,MySql,Oracle等支流数据库。 这是咱们平时十分相熟的需要了,依据需要咱们能够失去如下类图: 简略工厂UML类图咱们将后面SqlHelper例子中的类图进行一次形象,就失去更通用的简略工厂模式类图了。其中对应关系如下: Client:SqlHelperSimpleFactory:DbConnectionFactoryAbstractProduct:DbConnectionProduct1、Product2:SqlConnection、MySqlConnection 定义简略工厂模式是由一个工厂对象决定创立出哪一种产品类的实例。因为简略工厂通常会应用静态方法实现,因而也叫做动态工厂模式,它不属于23种GOF设计模式之一。 优缺点长处 实现了对责任的宰割,隔离了变动,因为它提供了专门的工厂类用于创建对象。通过配置文件,能够在不批改任何客户端代码的状况下更换和减少新的具体产品类,在肯定水平上进步了零碎的灵活性。毛病 集中了所有实例的创立逻辑,违反了繁多职责准则扩大艰难,一旦增加新产品就不得不批改工厂逻辑,违反了开闭准则工厂办法案例改良因为简略工厂模式不满足开闭准则,因而,咱们须要对其进行改良,将简略工厂进行一次形象,而后让每个具体的工厂子类负责生产对应的产品,具体改良如下: UML类图同样的,咱们进行一次形象,就失去工厂办法模式的类图了。 定义定义一个工厂父类,工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。行将类的实例化提早到工厂类的子类中实现,即由子类来决定应该实例化哪一个类。 优缺点长处: 满足各种设计准则毛病:类的个数成倍增加,减少了零碎的复杂度形象工厂需要扩大(参数化查问)当然,咱们晓得,工作中,更通用SqlHelper没有这么简略,比方,咱们至多须要参数化查问,避免用户的SQL脚本注入攻打。依据工厂办法模式的思路进一步改良,如下图所示: 不难发现,随着需要的减少,会呈现如下问题: 类的数量成倍增长无奈保障类之间的依赖关系改良基于这些问题,咱们持续改良,将多个互相关联的工厂(DbConnect和DbParameter应用时通常有密切联系)合并,失去如下类图: UML类图总结出更形象的类图如下: 定义形象工厂是工厂办法的升级版,为相干或者相互依赖的对象提供一个对立的接口,而且无需指定他们的具体实现类。 优缺点长处 对产品族进行束缚,封装性好毛病 产品族扩大艰难,增加一个产品须要批改形象和具体工厂类,违反开闭准则。总结简略工厂模式因为违反了泛滥设计准则,因而,很多时候会被视为是一种反模式而不是设计模式,然而因为面向对象设计语言中反射机制的存在,使得简略工厂模式应用的反而最为宽泛; 工厂办法尽管时最满足设计准则的,然而因为它会使零碎变得过于简单,因而,反而用的起码; 形象工厂模式更多体现的对产品族的束缚,同时,绝对于工厂办法模式,也升高了零碎的复杂度,极其状况下,如果形象工厂模式中的产品族只有一个产品,那么形象工厂模式也就进化成了工厂办法模式。因而,很多人说形象工厂模式是工厂的工厂,此观点是值得商讨的。 视频分享链接更多内容请关注公众号:

August 24, 2020 · 1 min · jiezi

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

面向对象个性封装:暗藏外部实现;继承:复用现有代码;多态:改写对象行为。 指标面向对象设计的指标是设计出高内聚、低耦合的应用程序,最大水平的实现程序的复用,以应答简单的需要变动。 设计准则繁多职责准则 一个类只负责一个性能畛域中的相应职责。依赖倒置准则 高层模块不应该依赖于低层模块,二者都应该依赖于形象形象不应该依赖于细节,细节该当依赖于形象。换言之,要面向接口(抽象类)编程,而不是面向实现编程。开闭准则 一个软件实体该当对扩大凋谢,对批改敞开。即软件实体应尽量在不批改原有代码的状况下进行扩大。接口隔离准则 应用多个专门的接口,而不应用繁多的总接口。里氏替换准则 所有基类呈现的中央必然能被子类替换,且性能不会产生影响。合成复用准则 尽量应用对象组合/聚合,而不是继承来达到复用的目标。迪米特准则 也叫最小常识准则,一个软件实体该当尽可能少地与其余实体产生相互作用。类与类之间的耦合度应尽量的低,这样如果类发生变化,影响才会最小。 只与间接的敌人通信,不跟陌生人谈话。开闭准则是指标,里氏代换准则是根底,依赖倒置准则是伎俩。设计准则的核心思想是: 隔离变动;针对接口编程,而不是针对实现编程。设计模式模式模式就是对前人积攒的教训的形象和升华。简略地说,就是从一直反复呈现的事件中发现和形象出法则,并解决同一类问题的经验总结,在软件工程畛域中的模式可分为三个档次。 习用法: 最底层,语言相干,如援用计数,智能指针,垃圾收集等。设计模式: 中层,语言无关,如工厂模式,策略模式等。架构模式: 最高层,语言无关,用于高层决策,实现架构复用,如C/S架构,B/S架构,微服务架构等。 说到设计模式就不得不提GOF的《设计模式-可复用面向对象软件的根底》这本书了,它奠定了设计模式在整个软件工程畛域的根底,副标题中的可复用和面向对象两个关键词失当的点明了设计模式的核心思想。设计模式依据其目标可分为创立型,结构型和行为型三种类型。 分类创立型 创立型模式次要用于创建对象,次要有工厂办法模式、形象工厂模式、单例模式、建造者模式、原型模式。结构型 结构型模式次要用于解决类或对象的组合,次要有适配器模式、装璜器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。行为型 行为型模式次要用于形容对类或对象之间的交互及职责调配,次要有策略模式、模板办法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。总结高内聚、低耦合 是面向对象设计最终要实现的指标,七大设计准则是指导方针,而设计模式是最终实际经验总结。这就像武侠小说一样,成为武林高手(高内聚、低耦合)是指标,而七大设计准则好比内功心法,设计模式就好比文治招式。学习招式是为了锻炼内功心法,当心法融汇贯通时,拈花摘叶皆可伤人,具体招式反而不再重要。当然,学了招式,在成为武林高手之前,也不能始终闭关修炼,还须要有高手过招,这就是要去学习优良的框架了,跟高手进行思维上的碰撞。然而,无论如何,学习招式是第一步,且行且珍惜! 视频分享链接更多内容请关注公众号:

August 24, 2020 · 1 min · jiezi

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

1.建造者模式1.1盖房我的项目需要盖房我的项目需要(1) 须要建房子:这一过程为打桩、砌墙、封顶(2) 房子有各种各样的,比方一般房,高楼,别墅,各种房子的过程尽管一样,然而要求不要雷同的. 1.2传统形式解决盖房需要(1)思路剖析 (2)代码实现 public abstract class AbstractHouse { //打地基 public abstract void buildBasic(); //砌墙 public abstract void buildWalls(); //封顶 public abstract void roofed(); public void build() { buildBasic(); buildWalls(); roofed(); } }public class CommonHouse extends AbstractHouse { @Override public void buildBasic() { // TODO Auto-generated method stub System.out.println(" 一般房子打地基 "); } @Override public void buildWalls() { // TODO Auto-generated method stub System.out.println(" 一般房子砌墙 "); } @Override public void roofed() { // TODO Auto-generated method stub System.out.println(" 一般房子封顶 "); }}public class Client { public static void main(String[] args) { CommonHouse commonHouse = new CommonHouse(); commonHouse.build(); }}1.3传统形式解决盖房需要问题剖析(1) 长处是比拟好了解,简略易操作。(2) 设计的程序结构,过于简略,没有设计缓存层对象,程序的扩大和保护不好. 也就是说,这种设计方案,把产品(即:房子) 和 创立产品的过程(即:建房子流程) 封装在一起,耦合性加强了。(3) 解决方案:将产品和产品建造过程解耦,即应用建造者模式 ...

August 23, 2020 · 2 min · jiezi

关于设计模式:设计模式-总结

August 18, 2020 · 0 min · jiezi

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

装璜者模式结构型模式装璜者模式(Decorator Pattern)容许向一个现有的对象增加新的性能,同时又不扭转其构造。它是作为现有的类的一个包装。 这种模式创立了一个装璜类,用来包装原有的类,并在放弃类办法签名完整性的前提下,提供了额定的性能。 介绍用意: 动静地给一个对象增加一些额定的职责。就减少性能来说,装璜者模式相比生成子类更为灵便。 次要解决: 个别的,咱们为了扩大一个类常常应用继承形式实现,因为继承为类引入动态特色,并且随着扩大性能的增多,子类会很收缩。 何时应用: 在不想减少很多子类的状况下扩大类。 如何解决: 将具体性能职责划分,同时继承装璜者模式。 要害代码: 1、Component 类充当形象角色,不应该具体实现。 2、润饰类援用和继承 Component 类,具体扩大类重写父类办法。 利用实例: 1、孙悟空有 72 变,当他变成"庙宇"后,他的基本还是一只猴子,然而他又有了庙宇的性能。 2、不管一幅画有没有画框都能够挂在墙上,然而通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画能够被蒙上玻璃,装到框子里;这时画、玻璃和画框造成了一个物体。 具体实现 依据一个咖啡厅卖饮料和调味品的问题来解决。 第一步:创立形象Drink类 public abstract class Drink { /** * 形容 */ private String des; /** * 价格 */ private float price = 0.0f; public String getDes() { return des; } public void setDes(String des) { this.des = des; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } //计算费用的形象办法 public abstract float cost();}第二步:创立Coffee类 ...

August 13, 2020 · 2 min · jiezi

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

装璜者模式结构型模式装璜者模式(Decorator Pattern)容许向一个现有的对象增加新的性能,同时又不扭转其构造。它是作为现有的类的一个包装。 这种模式创立了一个装璜类,用来包装原有的类,并在放弃类办法签名完整性的前提下,提供了额定的性能。 介绍用意: 动静地给一个对象增加一些额定的职责。就减少性能来说,装璜者模式相比生成子类更为灵便。 次要解决: 个别的,咱们为了扩大一个类常常应用继承形式实现,因为继承为类引入动态特色,并且随着扩大性能的增多,子类会很收缩。 何时应用: 在不想减少很多子类的状况下扩大类。 如何解决: 将具体性能职责划分,同时继承装璜者模式。 要害代码: 1、Component 类充当形象角色,不应该具体实现。 2、润饰类援用和继承 Component 类,具体扩大类重写父类办法。 利用实例: 1、孙悟空有 72 变,当他变成"庙宇"后,他的基本还是一只猴子,然而他又有了庙宇的性能。 2、不管一幅画有没有画框都能够挂在墙上,然而通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画能够被蒙上玻璃,装到框子里;这时画、玻璃和画框造成了一个物体。 具体实现 依据一个咖啡厅卖饮料和调味品的问题来解决。 第一步:创立形象Drink类 public abstract class Drink { /** * 形容 */ private String des; /** * 价格 */ private float price = 0.0f; public String getDes() { return des; } public void setDes(String des) { this.des = des; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } //计算费用的形象办法 public abstract float cost();}第二步:创立Coffee类 ...

August 13, 2020 · 2 min · jiezi

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

观察者模式 详解 后续补充

August 13, 2020 · 1 min · jiezi

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

几种工厂模式

August 13, 2020 · 1 min · jiezi

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

三种单例模式

August 13, 2020 · 1 min · jiezi

关于设计模式:设计模式21-中介模式

1. 简介中介模式的英文翻译是 Mediator Design Pattern。在 GoF 中的《设计模式》一书中,它是这样定义的: Mediator pattern defines a separate (mediator) object that encapsulates the interaction between a set of objects and the objects delegate their interaction to a mediator object instead of interacting with each other directly.翻译成中文就是: 中介模式定义了一个独自的(中介)对象,来封装一组对象之间的交互。实际上,中介模式的设计思维跟中间层很像,通过引入中介这个中间层,将一组对象之间的交互关系(或者说依赖关系)从多对多(网状关系)转换为一对多(星状关系)。 原来一个对象要跟 n 个对象交互,当初只须要跟一个中介对象交互,从而最小化对象之间的交互关系,升高了代码的复杂度,进步了代码的可读性和可维护性。这里我画了一张对象交互关系的比照图。! 其中,左边的交互图是利用中介模式对右边交互关系优化之后的后果,从图中咱们能够很直观地看出,左边的交互关系更加清晰、简洁。提到中介模式,有一个比拟经典的例子不得不说,那就是航空管制。 为了让飞机在航行的时候互不烦扰,每架飞机都须要晓得其余飞机每时每刻的地位,这就须要时刻跟其余飞机通信。飞机通信造成的通信网络就会无比简单。这个时候,咱们通过引入“塔台”这样一个中介,让每架飞机只跟塔台来通信,发送本人的地位给塔台,由塔台来负责每架飞机的航线调度。这样就大大简化了通信网络。

August 11, 2020 · 1 min · jiezi