开闭原则

开闭原则:
面向对象编程领域中,规定“软件中的对象,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。该特性在产品化的环境中是特别有价值的,在这种环境中,改变源代码需要代码审查单元测试以及诸如此类的用以确保产品使用质量的过程。遵循这种原则的代码在扩展时并不发生改变,因此无需上述的过程。

里氏替换原则

里氏替换原则:
的内容可以描述为: “派生类(子类)对象可以在程式中代替其基类(超类)对象

接口隔离原则

接口隔离原则:
使用多个专门的接口比使用单一的总接口要好。
一个类对另外一个类的依赖性应当是建立在最小的接口上的。
一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。
“不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。”这个说得很明白了,再通俗点说,不要强迫客户使用它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。

依赖倒置原则

依赖倒置原则:
(Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
意图
面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变动时上层也要跟着变动,这就会导致模块的复用性降低而且大大提高了开发的成本。
面向对象的开发很好的解决了这个问题,一般情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即使实现细节不断变动,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序与实现细节的耦合度。

LRU算法

image.png

  1. public class LruCache {
  2. class DlinkedNode {
  3. int key;
  4. int value;
  5. DlinkedNode prev;
  6. DlinkedNode next;
  7. public DlinkedNode() {}
  8. public DlinkedNode(int _key, int _value) {key = _key; value = _value;}
  9. }
  10. private Map<Integer, DlinkedNode> cache = new HashMap<Integer, DlinkedNode>();
  11. private int size;
  12. private int capacity;
  13. private DlinkedNode head, tail;
  14. public LruCache(int capacity) {
  15. this.size = 0;
  16. this.capacity = capacity;
  17. // 使用伪头部和伪尾部节点
  18. head = new DlinkedNode();
  19. tail = new DlinkedNode();
  20. head.next = tail;
  21. tail.prev = head;
  22. }
  23. public int get(int key) {
  24. DlinkedNode node = cache.get(key);
  25. if (node == null) {
  26. return -1;
  27. }
  28. // 如果 key 存在,先通过哈希表定位,再移到头部
  29. moveToHead(node);
  30. return node.value;
  31. }
  32. public void put(int key, int value) {
  33. DlinkedNode node = cache.get(key);
  34. if (node == null) {
  35. // 如果 key 不存在,创建一个新的节点
  36. DlinkedNode newNode = new DlinkedNode(key, value);
  37. // 添加进哈希表
  38. cache.put(key, newNode);
  39. // 添加至双向链表的头部
  40. addToHead(newNode);
  41. ++size;
  42. if (size > capacity) {
  43. // 如果超出容量,删除双向链表的尾部节点
  44. DlinkedNode tail = removeTail();
  45. // 删除哈希表中对应的项
  46. cache.remove(tail.key);
  47. --size;
  48. }
  49. }
  50. else {
  51. // 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
  52. node.value = value;
  53. moveToHead(node);
  54. }
  55. }
  56. private void addToHead(DlinkedNode node) {
  57. node.prev = head;
  58. node.next = head.next;
  59. head.next.prev = node;
  60. head.next = node;
  61. }
  62. private void removeNode(DlinkedNode node) {
  63. node.prev.next = node.next;
  64. node.next.prev = node.prev;
  65. }
  66. private void moveToHead(DlinkedNode node) {
  67. removeNode(node);
  68. addToHead(node);
  69. }
  70. private DlinkedNode removeTail() {
  71. DlinkedNode res = tail.prev;
  72. removeNode(res);
  73. return res;
  74. }
  75. }