设计模式知识点整理

关于课程更多内容欢迎私信我领取~,也可去【若云轩】领取

1选择题

  1. 设计模式的关键要素:(名称、解决方案、效果、问题

设计模式的主要优点:(适应需求变化

  1. 1. 设计模式的关键要素:(名称、解决方案、效果、问题
  2. 1. 描述对象所能接受的全部请求的集合的是:(接口

外观模式违背开闭原则

2模式的应用

对象接口描述了该对象所能接受的全部请求的集合,因此任何匹配对象接口中型构的请求都可以发送给该对象。 设计模式通过确定接口的主要组成成分及经接口发送的数据类型,来帮助你定义接口。

  1. 1. 下列选项中不属于对象模式的是:模板方法模式

  2. 1. 为了使客户端以一致的方式处理树形结构中的叶子节点和容器节点,实现客户端的透明操作,组合模式中引入了:抽象构件类

  3. 当一个类希望由它的子类来指定它所创建的对象的时候,我们选择工厂模式

  4. 当一个系统应该独立于它的产品创建、构成和表示时,要使用抽象工厂模式

  5. 当一个系统要由多个产品系列中的一个来配置时,我们选择抽象工厂模式

  6. 一个应用程序使用了大量的对象,要使用享元模式

  7. 在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用代理模式

你想在不明确指定接收者的情况下,向对各对象中的一个提交一个请求时,要使用**职责链模式

  1. 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变,要使用观察者模式**

JDBC中的数据库驱动程序是适配器模式的一个应用实例。

策略模式适用于一个可动态选择算法的数据操作工具

在Windows中,应用程序快捷方式可以被视为代理模式的一个应用实例1

Java事件处理中的监听器接口是观察者模式的一个应用实例1

3模式对原则的体现

抽象工厂模式对“开闭原则”的支持呈现倾斜性 建造者模式:增加新的具体建造者无须修改及有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则” 原型模式:对已有的类进行改造时,必须修改其源代码,违背了“开闭原则”,

单例模式:单例类的职责过重,在一定程度上违背了单一职责原则。

适配器模式:符合开闭原则

桥接模式:有时类似多继承方案,多继承方案违背了“单一职责原则”

装饰模式:增加新的具体构件类与具体装饰类符合开闭原则

外观模式:实现“迪米特法则“,在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则” 迭代器模式:是单一职责原则”的完美体现 观察者模式:如果在具体层具有关联关系,系统的扩展性将受到一定的影响,增加新的具体目标类有时候需要修改原有观察者的代码,在一定程度上违反了“开闭原则”,但是如果原有观察者类无须关联新增的具体目标,则系统扩展性不受影响。

职责链模式:在系统中增加一个新的具体请求处理者无需修改原有系统的代码,只需要在客户端重新建链即可,从这一点来看符合开闭原则。

命令模式:增加新的具体命令无需修改原有系统源代码,包括客户类代码,满足开闭原则

解释器模式:增加新的表达式无需对现有表达式类进行修改,符合开闭原则

迭代器模式:满足开闭原则,是单一职责原则的完美体现 工厂方法模式体现了面向对象设计原则中的:开闭原则,依赖倒转原则,单一职责原则 实现开闭原则的关键是对系统进行抽象化 (3)将遍历聚合对象中数据的行为提取出来,封装到一个迭代器中,通过专门的迭代器来遍历聚合对象的内部数据,这就是迭代器模式的本质。迭代器模式是“单一职责原则”的完美体现。

中介者模式:是迪米特法则的典型应用,增加新的中介者和新的同事类都比较方便,更好的符合开闭原则

状态模式:对于可以切换状态的状态模式不满足“开闭原则”的要求。

策略模式:符合“开闭原则”

模版方法模式:符合“开闭原则””单一职责原则“

访问者模式:倾斜的“开闭原则” 与抽象工厂模式一样,访问者模式对“开闭原则”的支持也具有倾斜性,访问者模式只有在被访问的元素类结构稳定的情况下才能使用,也就是说尽量不要出现增加新元素的情况。在访问者模式中,增加新的元素需要在每一个访问者包括扣象访问者中增加对应的元素访问方法,将对系统进行较大自修改,这将违背“开闭原则”旦是在访问者模式中对元素增加新的操作很方便,只需要增力一个新的访问者即可,将新的操作封装在新增访问者类中,无须对原有系统进行任何修改这符合“开闭原则”的要求此,访问者模式以一种倾斜的方式支持“开闭原则”,增加新访问者方便,但是增加新的元素很困难。

抽象工厂模式:与工厂方法模式一样,在本实例中,可以将具体工厂类的类名存储在配置文件(如XMI文件)中,再通过 DOM 和反射机制来生成工厂对象。在增加新的具体产品族时只需对应增加新的具体工厂即可,如果需要更换一个产品族,只需修改配置文件中的具体工厂类类名,无须修改源代码,符合开闭原则。但是如果要增加新的产品等级结构,每个工厂要生产一个新的类型的对象,则需要修改抽象工厂接口和所有的具体工厂类,从这个角度来看,抽象工厂模式违背了开闭原则。因此在使用抽象工厂模式时需要仔细分析所有的产品结构,避免在设计完成之后修改源代码,特别是抽象层的代码。

4各种模式适用情况:

1简单工厂模式:

(1)工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。 (2)客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数即可。

2工厂方法模式适用情况包括:

一个类不知道它所需要的对象的类;另一个类通过其子类来指定创建哪个对象;将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定。

3抽象工厂模式适用情况包括:

一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节;系统中有多于一个的产品族,而每次只使用其中某一产品族;属于同一个产品族的产品将在一起使用;系统提供一个产品类的库,所有的产品以同样的接口出现从而使客户端不依赖于具体实现。

4建造者模式适用情况包括:

需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性;需要生成的产品对象的属性相互依赖,需要指定其生成顺序;对象的创建过程独立于创建该对象的类;隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同类型的产品。

(5)原型模式适用情况包括:

创建新对象成本较大,新的对象可以通过原型模式对已有对象进行复制来获得;

系统要保存对象的状态,而对象的状态变化很小;

需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便。

(6)单例模式适用情况包括:

系统只需要一个实例对象;客户调用类的单个实例只允许使用一个公共访问点。

(7)适配器模式适用情况包括:

系统需要使用现有的类,而这些类的接口不符合系统的需要;

想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类一起工作。

8在以下情况下可以使用桥接模式。

(1)如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。 (2)抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。 (3)一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。 (4)虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。 (5)对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。

(9)组合模式适用情况包括:

需要表示一个对象的整体或部分层次;

让客户能够忽略不同对象层次的变化,客户端可以针对抽象构件编程,无须关心对象层次结构的细节;

对象的结构是动态的并且复杂程度不一样,但客户需要一致地处理它们。

(10)装饰模式适用情况包括:

在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责;需要动态地给一个对象增加功能,这些功能也可以动态地被撤销;当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

(11)外观模式适用情况包括:

要为一个复杂子系统提供一个简单接口;客户程序与多 个子系统之间存在很大的依赖性;在层次化结构中,需要定义系统中每一层的人口,使得层 与层之间不直接产生联系。

(12)享元模式适用情况包括:

一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费;

对象的大部分状态都可以外部化,可以将这些外部状态传入对象中;多次重复使用享元对象。

在使用享元模式时需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源,因此,应当在需要多次重复使用享元对象时才值得使用享元模式。

13代理模式适用情况包括

(1)远程(Remote)代理:为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又叫做大使(Ambassador)。 (2)虚拟(Virtual)代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。 (3)Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。 (4)保护(Protect or Access)代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。 (5)缓冲(Cache)代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。 (6)防火墙(Firewall)代理:保护目标不让恶意用户接近。 (7)同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。 (8)智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。 在这些种类的代理中,虚拟代理、远程代理和保护代理是最常见的代理模式。不同类型的代理模式有不同的优缺点,它们应用于不同的场合。

(14)职责链模式适用情况包括:

有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定;

在不明确指定接收者的情况下,向多个对象中的一个提交一个请求;

可动态指定一组对象处理请求。

15命令模式适用情况包括:

需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互;

需要在不同的时间指定请求、将请求排队和执行请求;

需要支持命令的撤销操作和恢复操作;需要将一组操作组合在一起,即支持宏命令。

(16)解释器模式适用情况包括:

可以将一个需要解释执行的语言中的句子表示为一个抽象语法树;

一些重复出现的问题可以用一种简单的语言来进行表达;

文法较为简单且效率不是关键问题。

(17)迭代器模式适用情况包括:

访问一个聚合对象的内容而无须暴露它的内部表示;需要为聚合对象提供多种遍历方式;

为遍历不同的聚合结构提供一个统一的接口。

18在以下情况下可以使用中介者模式:

(1)系统中对象之间存在复杂的引用关系,产生的相互依赖关系结构混乱且难以理解。 (2)一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象。 (3)想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。可以通过引入中介者类来实现,在中介者中定义对象交互的公共行为,如果需要改变行为则可以增加新的中介者类。

19在以下情况下可以使用备忘录模式:

(1)保存一个对象在某一个时刻的状态或部分状态,这样以后需要时它能够恢复到先前的状态。 (2)如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性,一个对象不希望外界直接访问其内部状态,通过负责人可以间接访问其内部状态。

20在以下情况下可以使用观察者模式:

(1)一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。 (2)一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。 (3)一个对象必须通知其他对象,而并不知道这些对象是谁。 (4)需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象······可以使用观察者模式创建一种链式触发机制。

21在以下情况下可以使用状态模式:

(1)对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为,如银行账号,具有不同的状态时其行为有所差异(有些状态既能存款又能取款,有些状态能存款但是不能取款)。 (2)代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,使客户类与类库之间的耦合增强。在这些条件语句中包含了对象的行为,而且这些条件对应于对象的各种状态。

22在以下情况下可以使用策略模式。

(1)如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 (2)一个系统需要动态地在几种算法中选择一种,那么可以将这些算法封装到一个个的具体算法类里面,而这些具体算法类都是一个抽象算法类的子类。换言之,这些具体算法类均有统一的接口,由于多态性原则,客户端可以选择使用任何一个具体算法类,并只需要维持一个数据类型是抽象算法类的对象。 (3)如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并且体现面向对象设计思想。 (4)不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法和相关的数据结构,提高算法的保密性与安全性。

23在以下情况下可以使用模板方法模式:

(1)一次性实现一个算法的不变部分,并将可变行为留给子类来实现。 (2)各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。首先需要识别现有代码中的不同之处,并且将不同之处分离为新的操作;然后,用一个调用这些新的操作的模板方法来替换这些不同的代码。 (3)对一些复杂的算法进行分割,将其算法中固定不变的部分设计为模板方法和父类具体方法,而一些可以改变的细节由其子类来实现。 (4)控制子类的扩展。模板方法只在特定点调用钩子方法,这样就只允许在这些点进行扩展,也就是说对于某些方法,可以通过钩子方法来进行扩展,而对于不能进行扩展的方法可以将其定义为final方法,对算法的扩展进行有效的控制和约束。

24在以下情况下可以使用访问者模式:

(1)一个对象结构包含很多类型的对象,希望对这些对象实施一些依赖其具体类型的操作。在访问者中针对每一种具体的类型都提供了一个访问操作,不同类型的对象可以有不同的访问操作。 (2)需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。访问者模式使得我们可以将相关的访问操作集中起来定义在访问者类中,对象结构可以被多个不同的访问者类所使用,将对象本身与对象的访问操作分离。 (3)对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。

5hashmap,HashSet,arraylist,iterator用法

Integer.parseInt(String s):此方法将字符串 s 转换为一个整数

Java语言中并没有直接称为"哈希图"的容器,但是有HashMap这个类,它实现了Map接口,提供了一种键值对的数据结构,可以以O(1)的时间复杂度进行查找、插入和删除操作。

下面是一个简单的HashMap的使用例子:

  1. import java.util.HashMap;

  2. import java.util.Map;

  3. public class Main {

  4. public static void main(String[] args) {

  5. // 创建一个HashMap对象

  6. Map<String, Integer> map = new HashMap<>();

  7. map.put("apple", 1);

  8. map.put("banana", 2);

  9. map.put("cherry", 3);

  10. int apple = map.get("apple"); // 返回1

  11. System.out.println("apple: " + apple);

  12. // 检查元素是否存在

  13. boolean hasApple = map.containsKey("apple"); // 返回true

  14. System.out.println("has apple: " + hasApple);

  15. for (Map.Entry<String, Integer> entry : map.entrySet()) {

  16. String key = entry.getKey();

  17. int value = entry.getValue();

  18. System.out.println(key + ": " + value);

  19. map.remove("banana");

  20. System.out.println("After removing banana:");

  21. for (Map.Entry<String, Integer> entry : map.entrySet()) {

  22. String key = entry.getKey();

  23. int value = entry.getValue();

  24. System.out.println(key + ": " + value);

这个例子展示了如何创建一个HashMap,插入元素,获取元素,检查元素是否存在,以及删除元素。HashMap的一个重要特性是它的键是唯一的,如果你尝试插入一个已经存在的键,那么它的值会被新的值替换。

  1. HashMap<String, Integer> map = new HashMap<>();

  2. // 第一种效率最差。因为是先获取到键,再获取到值。

  3. Set<String> strings = map.keySet();

  4. for (String key : strings) {

  5. Integer value = map.get(key);

  6. System.out.println(key+ " - " +value);

  7. // 第二种,获取到迭代器。性能比第一种好,一次取值

  8. Set<Map.Entry<String, Integer>> entries = map.entrySet();

  9. Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();

  10. while (iterator.hasNext()) {

  11. Map.Entry<String, Integer> next = iterator.next();

  12. String key = next.getKey();

  13. Integer value = next.getValue();

  14. System.out.println(key + " - " + value);

  15. Set<Map.Entry<String, Integer>> es = map.entrySet();

  16. for (Map.Entry<String,Integer> entry : es) {

  17. String key = entry.getKey();

  18. Integer value = entry.getValue();

  19. System.out.println(key + " - " + value);

HashSet是Java集合框架的一部分,它实现了Set接口。HashSet是一个不允许重复的无序集合,它的主要特点是不允许有重复元素。

以下是使用HashSet的一些基本操作:

  1. 添加元素:可以使用add()方法添加元素,如set.add("apple")

  2. 移除元素:可以使用remove()方法移除元素,如set.remove("apple")

  3. 检查元素是否存在:可以使用contains()方法检查元素是否存在,如set.contains("apple")将返回一个布尔值,如果"apple"存在于集合中则返回true,否则返回false。

  4. 获取HashSet的大小:可以使用size()方法获取集合的大小。

  5. 清空集合:可以使用clear()方法清空集合,这将删除集合中的所有元素。

  6. 检查集合是否为空:可以使用isEmpty()方法,如果集合为空,将返回true,否则返回false。

  7. 将另一个集合添加到当前集合:可以使用addAll()方法,如set.addAll(otherSet)

  8. 遍历HashSet:可以使用for-each循环或者迭代器遍历HashSet。注意,由于HashSet是无序的,所以遍历的顺序可能每次都不同。

ArrayList 是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。

添加元素

ArrayList 类提供了很多有用的方法,添加元素到 ArrayList 可以使用 add() 方法:

实例

import java.util.ArrayList;

public class RunoobTest { public static void main(String[] args) { ArrayList sites = new ArrayList(); sites.add("Google"); sites.add("Runoob"); sites.add("Taobao"); sites.add("Weibo"); System.out.println(sites); } }

以上实例,执行输出结果为:

[Google, Runoob, Taobao, Weibo]

访问元素

访问 ArrayList 中的元素可以使用 get() 方法:

实例

import java.util.ArrayList;

public class RunoobTest { public static void main(String[] args) { ArrayList sites = new ArrayList(); sites.add("Google"); sites.add("Runoob"); sites.add("Taobao"); sites.add("Weibo"); System.out.println(sites.get(1)); // 访问第二个元素 } }

注意:数组的索引值从 0 开始。

以上实例,执行输出结果为:

Runoob

修改元素

如果要修改 ArrayList 中的元素可以使用 set() 方法:

实例

import java.util.ArrayList;

public class RunoobTest { public static void main(String[] args) { ArrayList sites = new ArrayList(); sites.add("Google"); sites.add("Runoob"); sites.add("Taobao"); sites.add("Weibo"); sites.set(2, "Wiki"); // 第一个参数为索引位置,第二个为要修改的值 System.out.println(sites); } }

以上实例,执行输出结果为:

[Google, Runoob, Wiki, Weibo]

删除元素

如果要删除 ArrayList 中的元素可以使用 remove() 方法:

实例

import java.util.ArrayList;

public class RunoobTest { public static void main(String[] args) { ArrayList sites = new ArrayList(); sites.add("Google"); sites.add("Runoob"); sites.add("Taobao"); sites.add("Weibo"); sites.remove(3); // 删除第四个元素 System.out.println(sites); } }

以上实例,执行输出结果为:

[Google, Runoob, Taobao]

计算大小

如果要计算 ArrayList 中的元素数量可以使用 size() 方法:

实例

import java.util.ArrayList;

public class RunoobTest { public static void main(String[] args) { ArrayList sites = new ArrayList(); sites.add("Google"); sites.add("Runoob"); sites.add("Taobao"); sites.add("Weibo"); System.out.println(sites.size()); } }

以上实例,执行输出结果为:

4

迭代数组列表

我们可以使用 for 来迭代数组列表中的元素:

实例

import java.util.ArrayList;

public class RunoobTest { public static void main(String[] args) { ArrayList sites = new ArrayList(); sites.add("Google"); sites.add("Runoob"); sites.add("Taobao"); sites.add("Weibo"); for (int i = 0; i < sites.size(); i++) { System.out.println(sites.get(i)); } } }

以上实例,执行输出结果为:

  1. Integer.parseInt(String s):此方法将字符串 s 转换为一个整数。如果字符串 s 是整数,则方法返回该整数;否则,会抛出一个 NumberFormatException
  1. boolean isEqual = str1.equalsIgnoreCase(str2); // isEqual 的值为 true

Iterator的主要方法包括hasNext()和next()。hasNext()方法返回一个布尔值,指示是否还有更多的元素可以遍历。next()方法返回集合中的下一个元素,并将指针移动到下一个元素。

使用Iterator,可以遍历任何实现了Iterable接口的集合,例如List、Set和Map等。通过使用Iterator,开发人员可以轻松地遍历和操作集合中的元素。

当然,这里有一个使用Java中Iterator的简单例子:

  1. import java.util.*;

  2. public class Main {

  3. public static void main(String[] args) {

  4. // 创建一个ArrayList

  5. List<String> list = new ArrayList<String>();

  6. list.add("Apple");

  7. list.add("Banana");

  8. list.add("Cherry");

  9. list.add("Date");

  10. list.add("Elderberry");

  11. // 获取list的迭代器

  12. Iterator<String> it = list.iterator();

  13. // 使用迭代器遍历list

  14. while(it.hasNext()){

  15. String fruit = it.next();

  16. System.out.println(fruit);

在这个例子中,我们创建了一个包含若干水果名称的ArrayList。然后,我们获取了这个List的Iterator,并使用这个Iterator遍历了List中的每个元素,并打印出来。这个例子展示了如何使用Iterator的基本方法。

本文使用 文章同步助手 同步

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容