原文链接https://www.nowcoder.com/discuss/421353?channel=-1&source_id=1

设计原则

1. 开闭原则(Open Close Principle)

开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类

2. 里氏替换原则(Liskov Substitution Principle)

  • 里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。
  • 里氏代换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。
  • 里氏代换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。

包含的含义:

  • 子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法
  • 子类中可以增加自己特有的方法
  • 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松

原文链接:https://www.douban.com/note/363404356/

3. 依赖倒转原则(Dependence Inversion Principle)

 针对接口编程,依赖于抽象而不依赖于具体

可参见:https://blog.csdn.net/king123456man/article/details/81626127

4.接口隔离原则(Interface Segregation Principle)

使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思:降低依赖,降低耦合。

可参见:https://blog.csdn.net/king123456man/article/details/81626059

 5.迪米特法则(最少知道原则)(Demeter Principle)

 一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

6. 合成复用原则(Composite Reuse Principle)

软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

合成复用原则是通过将已有的对象纳入新对象中,作为新对象的成员对象来实现的,新对象可以调用已有对象的功能,从而达到复用。

原文链接:https://blog.csdn.net/u012361379/article/details/88605867

组合和聚合的区别见:https://www.cnblogs.com/daijux/p/11842796.html

设计模式

参考《图解设计模式》

 

一、创建型模式

 

工厂模式(Factory Pattern)https://juejin.im/entry/6844903474639929357

  • 简单工厂模式:定义一个工厂类,根据传入的参数不同,返回不同的实例。只有一个工厂类,封装了对象的创建过程。适用于需要创建的对象较少,不关心对象创建过程的场景。
  • 工厂模式:不再提供统一的工厂类来创建所有对象,而是每个对象都有一个对应的工厂类。有产品接口和工厂接口,工厂接口决定了产品的生产方式,工厂实现类说明了具体如何生产处理,具体生产哪一种产品。定义一个用于创建对象的接口,决定了实例的生产方式,让子类(工厂)决定将哪一个类(产品)实例化。

抽象工厂模式(Abstract Factory Pattern)
单例模式(Singleton Pattern)
建造者模式(Builder Pattern)
原型模式(Prototype Pattern)

 

二、结构型模式

 

适配器模式(Adapter Pattern)
桥接模式(Bridge Pattern)
过滤器模式(Filter、Criteria Pattern)
组合模式(Composite Pattern)
装饰器模式(Decorator Pattern)
外观模式(Facade Pattern)
享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)

 

三、行为型模式

 

责任链模式(Chain of Responsibility Pattern)
命令模式(Command Pattern)
解释器模式(Interpreter Pattern)
迭代器模式(Iterator Pattern)
中介者模式(Mediator Pattern)
备忘录模式(Memento Pattern)
观察者模式(Observer Pattern)
状态模式(State Pattern)
空对象模式(Null Object Pattern)
策略模式(Strategy Pattern)
模板模式(Template Pattern)
访问者模式(Visitor Pattern)

 

1. 适配器(Adapter)模式

Adapter模式有两种:

  • 类适配器模式(使用继承的适配器)
  • 对象适配器模式(使用委托的适配器)

示例程序1(使用继承的适配器)

要做的事情是使用Banner类编写一个实现了Print接口的类,也就是说要做一个将“交流100伏特电压”转换成“直流12伏特电压”的适配器。

 

 

 

 

 

 

 

 

 

 

 

 示例程序2(使用委托的示例程序)

在Java语言中,委托就是指将某个方法中的实际处理交给其他实例的方法。

Main类和Banner类与示例程序1中的内容完全相同,不过这里的Print不是借口而是类。PrintBanner类无法同时继承两个类,所以可以通过Banner的实例来调用Banner类中的方法。这样就形成了一种委托关系,当PrintBanner类的printWeak被调用的时候,并不是自己处理的,而是交给了其他实例(Banner类的实例)的showWithParen方法。

 

 

 

 Adapter模式中的登场角色

  • Target(对象):该角色负责定义所需的方法。示例程序中,由Print接口(使用继承时)和Print类(使用委托时)扮演此角色。
  • Client(请求者):该角色负责使用Target角色所定义的方法进行具体处理。由Main类扮演。
  • Adaptee(被适配):Adaptee是一个既持有既定方法的角色。由Banner类扮演。
  • Adapter(适配):Adapter模式的主人公。使用Adaptee角色的方法来满足Target角色的需求,这是Adapter模式的目的,也是Adapter角色的作用。由PrintBanner类扮演。

在类适配器模式中,Adapter角色通过集成来使用Adaptee角色,而在对象适配器模式中,Adapter角色通过委托来使用Adaptee角色。

 

 优点:

  • 接口可以转成自己希望的另一个接口
  • 提高了类的复用

缺点:过多地使用适配器,会让系统非常凌乱,不易整体进行把握。

2. 工厂(Factory Method)模式

用Template Method模式来构建生成实例的工厂,就是Factory Method模式。在工厂模式中,父类决定实例的生产方式,但并不决定所要生成的具体的类,具体的处理全部交给子类负责。这样就可以将生产实例的框架和实际负责生成实例的类解耦。

示例程序

制作身份证(ID卡),有5个类

Product类和Factory类属于framework包。这两个类组成了生成实例的框架。

IDCard类和IDCardFactory类负责实际的加工处理,它们属于idcard包。

还有Main类。

Product类:在这个框架中,定义了产品是“任意可以use的”东西。

 

 

 Factory类:在这个框架中,定义了工厂是用来“调用create方法生成Product实例”的。而create方法的实现是先调用createProduct生成产品,接着调用registerProduct注册产品。“生成产品”和“注册产品”的具体处理被交给了Factory类的子类负责。只要是工厂模式,在生成实例时就一定会用到Template Method模式。

 

 IDCard类:Product类的子类。

 

 IDCardFactory类:实现了“生成产品”和“注册产品”。

 

 

 

 Main类:制作和使用IDCard。

 

 Factort Method模式中的登场角色

父类(框架)的Creator角色和Product角色的关系与子类(具体加工)的ConcreteCreator角色和ConcreteProduct角色的关系是平行的。

 

  • Product(产品):属于框架这一方,是一个抽象类。定义了工厂模式中生成的那些实例的所持有的接口。具体处理是由其子类ConcreteProduct角色决定。Product类扮演。
  • Creator(创建者):属于框架这一方,负责生产Product角色的抽象类,具体处理交由子类ConcreteCreator决定。Factory类扮演。
  • ConcreteProduct(具体的产品):属于具体加工这一方,决定了具体的产品。IDCard类扮演。
  • ConcreteCreator(具体的创建者):属于具体加工这一方,负责生产具体产品。IDCardFactory类扮演。

优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

3. 抽象工厂(Abstract Factory)模式

抽象工厂模式是围绕一个超级工厂创建其他的工厂。抽象工厂的工作是将抽象零件组装成抽象产品,不关心零件的具体实现,只关心接口。仅使用接口将零件组装成为产品。

优点:当一个产品类型(每一类中有多个产品)被设计成一起工作时,有良好的维护性。

缺点:产品类扩展困难。

4. 单例(Singleton)模式

确保只生成一个实例的模式。

示例程序

 

Singleton类

Singleton类的构造函数是private的,这是为了禁止从Singleton类外部调用构造函数生成实例。Singleton模式的作用在于可以确保任何情况下都只能生成一个实例,必须设置构造函数为private。

getInstance方法便于程序从Singleton类外部获取Singleton类唯一的实例,声明为static类型是为了可以直接用类名调用这个方法,而不需要生成实例去调用。

 

 Main类

 

 

 

 Singleton模式中的登场角色

只有Singleton这一个角色,这个角色中有一个返回唯一实例的static方法。

5. 代理模式

示例程序见《图解设计模式》中的打印机示例,只有真正需要打印时才生成“干重活”的Printer类,否则都交给代理人PrinterProxy类来做。

作用:一个类代理另一个类的功能。

应用场景:使用代理人来提升处理速度

  1. 假如在一个大型系统的初始化过程中,存在大量的耗时处理。如果在启动系统时连那些暂时不会被使用的功能也初始化了,那么启动时间将会非常漫长,这将会引发用户的不满。而如果我们只在需要使用某个功能时才将其初始化,则可以帮助我们改善用户体验。

  2. 可以在文本中嵌入图形对象的文本编辑器。 为了生成这些图形对象,需要读取图片文件,很耗时。因为如果在打开文档时就生成所有的图形对象,就会导致打开时间过长。所以,最好是当用户浏览至文本中各个图形对象时,再去生成它们的实例。

  3. HTTP代理,位于HTTP服务器(Web服务器)和HTTP客户端(Web浏览器)之间,为Web页面提供高速缓存等功能。可以认为它是一种代理模式。通过Web浏览器访问Web页面时,并不会每次都取访问远程Web服务器来获取页面的内容,而是会先去获取HTTP代理缓存的页面。只有当需要最新页面内容或者页面的缓存期限过期时,才会访问远程Web服务器。

角色:

  • Subject(主体):定义了使Proxy角色和RealSubject角色之间具有一致性的接口。由于存在Subject角色,所以Client角色不必在意它所使用的究竟是Proxy角色还是RealSubject角色。
  • Proxy(代理人):Proxy角色会尽量处理来自Client角色的请求。只有自己不能处理时,才会交给RealSubject角色。实现了Subject角色中定义的接口。
  • RealSubject(实际的主体):在Proxy角色无法胜任工作时出场。实现了Subject角色中定义的接口。
  • Client(请求者):使用Proxy模式的角色。

 

 缺点:由于在客户端和真实主体之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。

6. 装饰器模式

概念:不论是蛋糕、奶油蛋糕、草莓蛋糕还是生日蛋糕,它们的核心都是蛋糕。程序中的对象与蛋糕十分相似。首先有一个相当于蛋糕的对象,然后像不断地装饰蛋糕一样地对其增加功能,它就变成了使用目的更加明确的对象。

作用:对已有的业务逻辑进一步的封装,使其增加额外的功能。即向一个现有的对象添加新的功能,同时又不改变其结构。

示例程序见《图解设计模式》中的文字装饰边框示例。装饰边框与被装饰物都继承自Display类,也就是装饰边框与被装饰物具有了相同的方法,每一个装饰类中都有display字段,这个字段就相当于要被装饰的蛋糕。

角色:

  • Component:增加功能时的核心角色。相当于装饰前的蛋糕。它只是定义了蛋糕的接口。
  • ConcreteComponent:实现了Component角色定义的接口的具体蛋糕。
  • Decorator(装饰物):具有与Component角色相同的接口。在内部保存了被装饰对象——Component角色。
  • ConcreteDecorder(具体的装饰物):是具体的Decorator角色。

 

优点:可以提供比继承更多的灵活性。在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

缺点:多层装饰比较复杂。 

7. 观察者(Observer)模式

它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使它们自动更新自己。Observer模式适用于根据对象状态进行相应处理的场景。

示例程序见《图解设计模式》,观察者将观察一个会生产数值的对象,并将生成数值的结果显示出来。不同的观察者的显示方式不一样。

角色:

  • Subject(观察对象):表示观察对象。Subject角色定义了注册观察者和删除观察者的方法。此外,还声明了“获取现在的状态”的方法。
  • ConcreteSubject(具体的观察对象):表示具体的被观察对象。当自身状态发生变化后,它会通知所有已经注册的Observer角色。
  • Observer(观察者):负责接收来自Subject角色的状态变化通知。为此,声明了update方法。
  • ConcreteObserver(具体的观察者):表示具体的观察者。当它的update方法被调用后,会去获取要观察的对象的最新状态。

 

 

 优点:

  • 观察者模式在被观察者和观察者之间建立一个抽象的耦合。
  • 观察者模式支持广播通讯。被观察者会向所有的登记过的观察者发出通知。

缺点:

  • 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
  • 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃

  • 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

应用场景:

  • 聊天室程序,服务器转发信息给所有客户端。

  • 网络游戏,服务器将客户端状态进行分发。

  • 邮件订阅等。

常见问题

1. 装饰着和代理模式的区别

装饰着模式关注的是对象的动态添加功能。代理模式关注的是对对象的访问控制,对它的用户隐藏对象的具体信息。

2. 装饰着模式和适配器模式

  • 装饰者模式和被装饰的类要实现同一个接口,或者装饰类是被装饰的类的子类。适配器模式和被适配的类具有不同的接口

  • 适配器模式被用于桥接两个接口,而装饰模式的目的是在不修改类的情况下给类增加新的功能

3. 工厂模式与抽象工厂模式的区别

工厂模式在增加一个新的产品时,就要相应的增加一个制作产品的工厂;抽象工厂模式是工厂方法模式的进一步延伸,由于它提供了功能更为强大的工厂类并且具备较好的可扩展性。

个人觉得这个区别在于产品,如果产品单一,最合适用工厂模式,但是如果有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。再通俗深化理解下:工厂模式针对的是一个产品等级结构 ,抽象工厂模式针对的是面向多个产品等级结构的。

4. 说出几个在JDK库中使用的设计模式

https://www.cnblogs.com/he-px/p/7510869.html

posted on 2020-07-10 15:34  小小糖果tt  阅读(376)  评论(0)    收藏  举报