Java基础(八)-设计模式

一、六大原则
  • 单一职责:一个类,应该仅有一个引起它变化的原因。即类有且仅有一个功能,切忌大包大揽。
  • 依赖倒置:针对接口编程,依赖于抽象而不依赖于具体。以此降低耦合,它是开闭原则的基础。
  • 开闭原则:类、模块、函数对拓展开放对修改关闭。即代码功能拓展尽量实现热插拔而非修改原有代码。
  • 里式替换:所有引用父类的地方必须能透明使用其子类。即子类可以扩展父类的功能,但不能改变父类原有的功能。
  • 接口隔离:一个类对另一个类的依赖应该建立在最小接口上。
  • 迪米特法则:一个对象应当尽可能少地与其他对象发生相互作用。
二、UML图

在UML类图中,常见的有以下几种关系:

  • 泛化(Generalization)继承
  • 实现(Realization)实现接口
  • 依赖(Dependency) 局部变量、方法形参
  • 关联(Association)成员变量(平等关系)
  • 聚合(Aggregation)成员变量(has-a 关系,整体不拥有部分的生命周期)
  • 组合(Composition)成员变量(contains-a 关系,整体拥有部分的生命周期)

图标示例:


2.1 泛化(Generalization)

继承
ClassB继承ClassA

2.2 实现(Realization)

实现接口
ClassB实现InterfaceA接口

starUML是如上表示,标准是虚线+实箭头

2.3 依赖(Dependency)

局部变量、方法形参

class Person{
   fun buyCar(count:Int){
       val car = Car()
       car.buy(count)
   }
}
2.4 关联(Association)

成员变量(平等关系)

class Person{
  val car = Car()
fun buyCar(count:Int){
    car.buy(count)
   }
}
2.5 聚合(Aggregation)

成员变量(has-a 关系,整体不拥有部分的生命周期)

class GooseGroup(var goose: Goose) {}
2.6 组合(Composition)

成员变量(contains-a 关系,整体拥有部分的生命周期)

class Goose {
   var wings: Wings
   init {
       wings = Wings()
   }
}

关联、聚合、组合需要结合上下文来判断。

几种关系的强弱程度:
泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖

三、设计模式


23种设计模式分类
创建型模式

1)单例模式
定义:保证一个类仅有一个实例供全局使用。


常见的实现方式有:懒汉、饿汉、double check、静态内部类、枚举。
保证线程安全+懒加载:推荐double check 或者 静态内部类两种方式

double check:

public class Singleton {  
      private volatile static Singleton singleton;  
      private Singleton (){
      }   
      public static Singleton getInstance() {  
      if (singleton== null) {  
          //首先通过synchronized来保证同一时刻只有一个线程能操作
          synchronized (Singleton.class) {  
          //拿到锁之后还需要再判一次空,可能之前持锁线程已经创建了实例了
          if (singleton== null) {  
             //singleton是引用类型,不具备原子性,因此可能发生指令重排。
             //正常情况:实例化对象的流程:
             //1.在堆上开辟空间
             //2.属性初始化
             //3.将栈上空间指向堆。
             //正常情况是1->2->3 ,重排可能为1->3->2
             //由于3步骤先执行,singleton已经不为空了,这时候其他进程访问getInstance直接return 对象,但是当前初始化并没有完成,出现问题。因此可以使用volatile来保证有序性,防止指令重排。
              singleton= new Singleton();  
          }  
         }  
     }  
     return singleton;  
     }  
}

静态内部类:

public class Singleton {
    private Singleton(){
    }
//延迟加载:静态内部类与外部类没有绑定关系,只有被调用到才会装载
      public static Singleton getInstance(){  
        return SingletonHolder.sInstance;  
    }  
    //线程安全:静态初始化由虚拟机保证线程安全。Java 类加载的初始化过程中,编译器按语句在源文件中出现的顺序,
   //依次自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并产生 <clinit>() 方法, 
   //虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,
   //那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。
    private static class SingletonHolder {  
        private static final Singleton sInstance = new Singleton();  
    }  
}

使用区别:静态内部类这种形式不支持传参,传参的情况下可以选择double check

2) 工厂三兄弟:简单工厂、工厂方法、抽象工厂
定义:对对象的实例化进行统一管理。

  • 简单工厂:一个电脑工厂生产苹果电脑、惠普电脑、联想电脑。
  • 工厂方法:对电脑工厂进行拆分,苹果电脑工厂生产苹果电脑、惠普电脑工厂生产惠普电脑。
  • 抽象工厂:引入产品簇概念,苹果工厂生产苹果手机、苹果电脑、苹果平板,华为工厂生产华为手机、华为电脑、华为平板。

3)建造者模式
定义:将一个对象的构建与表示分离,一种更为优雅的对象属性赋值写法。

public class Computer {
   public String cpu;
   public String memory;
   public Computer() {
        throw new RuntimeException("can't init");
   }

    private Computer(Builder builder) {
        cpu = builder.cpu;
       memory = builder.memory;
   }

    public static final class Builder {
        private String cpu;
       private String memory;
       public Builder() {
        }

        public Builder cpu(String val) {
            cpu = val;
           return this;
       }

        public Builder memory(String val) {
            memory = val;
           return this;
       }

        public Computer build() {
            return new Computer(this);
       }
    }
}

public static void main(String[] args) {
    Computer computer = new Computer.Builder()
            .cpu("aaa")
            .memory("ccc")
            .build();
}

4) 原型模式
定义:克隆,用于创建重复对象。

  • 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
  • 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
public abstract class Shape implements Cloneable {
   private String id;
   protected String type;
   
   abstract void draw();
   
   public Object clone() {
      Object clone = null;
      try {
         clone = super.clone();
      } catch (CloneNotSupportedException e) {
         e.printStackTrace();
      }
      return clone;
   }
}

public class Rectangle extends Shape {

   public Rectangle(){
     type = "Rectangle";
   }
 
   @Override
   public void draw() {
      System.out.println("rectangle draw");
   }
}

public class Square extends Shape {
 
   public Square(){
     type = "Square";
   }
 
   @Override
   public void draw() {
      System.out.println("square draw");
   }
}

public class ShapeCache {
    
   private static Hashtable<String, Shape> shapeMap 
      = new Hashtable<String, Shape>();
 
   public static Shape getShape(String shapeId) {
      Shape cachedShape = shapeMap.get(shapeId);
      return (Shape) cachedShape.clone();
   }
 
   public static void loadCache() {
      Rectangle rectangle = new Rectangle();
      rectangle.id = "1";
      shapeMap.put(rectangle.id,rectangle);

      Square square = new Square();
      square.id = "2";
      shapeMap.put(square.id,square);
   }
}

 public static void main(String[] args) {
      ShapeCache.loadCache();
 
      Shape clonedShape = (Shape) ShapeCache.getShape("1");
      System.out.println("Shape : " + clonedShape.type);        
 
      Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
      System.out.println("Shape : " + clonedShape2.type);               
   }
结构型模式

1) 代理模式
定义:为其他对象提供一种代理以控制对这个对象的访问。

静态代理:在代码运行前就已经存在了代理类的class编译文件

public interface IShop {
   void buy();
}

public class Tianmao implements IShop {
    @Override
   public void buy() {
        System.out.println("购买");
   }
}

public class Purchasing implements IShop {
    private IShop mShop;
   public Purchasing(IShop shop){
        mShop=shop;
   }

    @Override
   public void buy() {
        mShop.buy();
   }
}

public static void main(String[] args) {
    IShop purchasing=new Purchasing(new Tianmao());
   purchasing.buy();
}

动态代理:在代码运行时通过反射来动态的生成代理类的对象,并确定到底来代理谁。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicPurchasing implements InvocationHandler{
    private Object obj;
    public DynamicPurchasing(Object obj){
        this.obj=obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result=method.invoke(obj, args);
        return result;
    }
}

public static void main(String[] args) {
    IShop tianmao = new Tianmao();
   //创建动态代理
   DynamicPurchasing mDynamicPurchasing = new DynamicPurchasing(tianmao);
   ClassLoader loader = tianmao.getClass().getClassLoader();
   //动态创建代理类
   IShop purchasing = (IShop) Proxy.newProxyInstance(loader, new Class[]{IShop.class}, mDynamicPurchasing);
   purchasing.buy();
}

2) 装饰
定义:通过组合而非继承的方式,动态的来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。

3) 外观
定义:通过一个外观类使得整个系统的结构只有一个统一的高层接口,这样能降低用户的使用成本。

4) 享元
定义:对象池的概念

行为型模式

1) 策略
定义:使得策略可独立于使用它的客户而独立变化。

2) 模板
定义:父类定义抽象方法框架,将具体实现延迟到子类去执行,使得子类不能改变基本框架,但是可对特定步骤做差异化实现。

3) 观察者
定义:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,907评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,546评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,705评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,624评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,940评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,371评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,672评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,396评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,069评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,350评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,876评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,243评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,847评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,004评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,755评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,378评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,266评论 2 259

推荐阅读更多精彩内容

  • 创建型模式 工厂模式 工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设...
    隔墙送来秋千影阅读 2,600评论 0 11
  • 创建型模式 工厂模式 工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设...
    liuyang7519阅读 300评论 0 2
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,034评论 1 32
  • 爸爸玩游戏我生气了,不理他。孩子说我:你想想你看手机的时候我叫你你是不也不理我,你跟爸爸是一样的。说的我一想是那么...
    有凤来仪的简书阅读 155评论 0 0
  • 1. 初始化环境 打开cmd(windows)或者终端(Mac,Linux),进入项目文件夹,执行: 会得到如下提...
    WAchong阅读 2,540评论 0 1