设计模式

设计模式

概述:

  • 创建型模式:
    • 单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式
  • 结构型模式:
    • 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式
  • 行为型模式:
    • 模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式

OOP的七大原则

  • 开闭原则:对扩展开放,对修改关闭
  • 里氏替换原则:继承必须确保超类所拥有的性质在子类中仍然成立,尽量不要去破坏继承关系
  • 依赖倒置原则:面向接口编程,不要面向现实编程
  • 单一职责原则:控制类的粒度大小,将对象解耦,提高其内聚性。实现类要职责单一
  • 接口隔离原则:要为各个类建立它们所需要的专用接口
  • 迪米特法则:只与你的直接朋友交谈,不跟“陌生人”说话。降低对象之间的耦合度
  • 合成复用原则:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

1、单例模式

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

主要解决:一个全局使用的类的频繁地创建与销毁。

关键代码:构造函数是私有的。

饿汉式:

public class singleton{
    private singleton(){}
    private static singleton singlet=new singleton();
    public static singleton getSingleton(){
        return singlet;
    }
}

它基于classloader机制避免了多线程的同步问题,解决了多线程安全问题,但这种方式浪费内存。没有初始化Lazy

懒汉式:

public class Singleton{
    private Singleton(){}
    private static Singleton sing;
    public static Singleton getSingleton(){
        if(sing==null){
            sing=new Singleton();
        }
        return sing;
    }
}

因为没有加锁synchronized,多线程下不安全,初始化了Lazy

加锁后的懒汉式:

public class Singleton{
    private Singleton(){}
    private static Singleton sing;
    public static synchronized Singleton getSingleton(){
        if(sing==null){
            sing=new Singleton();
        }
        return sing;
    }
}

双重校验锁:

public class Singleton{
    private Singleton(){}
    private static Singleton sing;
    public volatile static Singleton getSingleton(){
        if(sing==null){
            synchronized(Singleton.class){
                if(sing==null){
                    sing=new Singleton();
                }
            }
        }
        return sing;
    }
}

线程安全,初始化了Lazy

静态内部类:

public class Singleton{
    private static class sing{
        private static final Singleton SING=new Singleton();
    }
    private Singleton(){}
    public static final Singleton getSingleton(){
        return sing.SING;
    }
}

线程安全,初始化了Lazy,这种方式能达到双重校验的一样的功效。

枚举:

public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}

线程安全,没有初始化Lazy,不能通过反射来调用该类的私有函数了,枚举中只有参数为(sting.class,int.class)构造器。因此,通过反射获取不到枚举的实例。

2、工厂模式

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

主要解决:主要解决接口选择问题。

关键代码:创建过程在其子类执行。

public interface Shape {
   void draw();
}
public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}
public class Square implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}
public class Circle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}
public class ShapeFactory {
    
   //使用 getShape 方法获取形状类型的对象
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
      } else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }
      return null;
   }
}
public class FactoryPatternDemo {
 
   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();
 
      //获取 Circle 的对象,并调用它的 draw 方法
      Shape shape1 = shapeFactory.getShape("CIRCLE");
 
      //调用 Circle 的 draw 方法
      shape1.draw();
 
      //获取 Rectangle 的对象,并调用它的 draw 方法
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
 
      //调用 Rectangle 的 draw 方法
      shape2.draw();
 
      //获取 Square 的对象,并调用它的 draw 方法
      Shape shape3 = shapeFactory.getShape("SQUARE");
 
      //调用 Square 的 draw 方法
      shape3.draw();
   }
}
//执行程序,输出的结果
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.

3、抽象工厂模式

意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。

主要解决:主要解决接口选择问题。

关键代码:在一个工厂里聚合多个同类产品。

手机、路由器的接口

package shejimoshi.abstactor;

public interface PhoneProduct {
    void start();
    void close();
    void daphone();
    void sendSm();
}
package shejimoshi.abstactor;

public interface RouterProduct {
    void start();
    void close();
    void openWifi();
    void setting();
}

小米、华为手机,小米、华为路由器的实现类

package shejimoshi.abstactor;
//小米手机
public class xiaomiPhone implements PhoneProduct {
    public void start() {
        System.out.println("小米手机开机");
    }

    public void close() {
        System.out.println("小米手机关机");
    }

    public void daphone() {
        System.out.println("用小米手机打电话");
    }

    public void sendSm() {
        System.out.println("用小米手机发短信");
    }
}
package shejimoshi.abstactor;
//小米路由器
public class xiaomiRouter implements RouterProduct {
    public void start() {
        System.out.println("小米路由器开机");
    }

    public void close() {
        System.out.println("小米路由器关机");
    }

    public void openWifi() {
        System.out.println("小米路由器打开wifi");
    }

    public void setting() {
        System.out.println("设置小米路由器");
    }
}
package shejimoshi.abstactor;
//华为手机
public class huaweiPhone implements PhoneProduct {
    public void start() {
        System.out.println("华为手机开机了");
    }

    public void close() {
        System.out.println("华为手机关机了");
    }

    public void daphone() {
        System.out.println("用华为手机打电话");
    }

    public void sendSm() {
        System.out.println("用华为手机发短信");
    }
}
package shejimoshi.abstactor;
//华为路由器
public class huaweiRouter implements RouterProduct {
    public void start() {
        System.out.println("华为路由器开机了");
    }

    public void close() {
        System.out.println("华为路由器关机了");
    }

    public void openWifi() {
        System.out.println("华为路由器打开了wifi");
    }

    public void setting() {
        System.out.println("设置华为路由器");
    }
}

这时,创建一个工厂接口,管理手机、路由器的生产

package shejimoshi.abstactor;

public interface Factory {
    PhoneProduct Phone();
    RouterProduct router();
}

小米,华为工厂的实现类

package shejimoshi.abstactor;
//小米生产工厂
public class xiaomiFactory implements Factory {
    public PhoneProduct Phone() {
        return new xiaomiPhone();
    }

    public RouterProduct router() {
        return new xiaomiRouter();
    }
}
package shejimoshi.abstactor;
//华为生产工厂
public class huaweiFactory implements Factory {
    public PhoneProduct Phone() {
        return new huaweiPhone();
    }

    public RouterProduct router() {
        return new huaweiRouter();
    }
}

测试

package shejimoshi.abstactor;

public class consumer {
    public static void main(String[] args) {
        System.out.println("================小米系列===================");
        xiaomiFactory xiaomiFactory = new xiaomiFactory();
        PhoneProduct phone = xiaomiFactory.Phone();
        phone.daphone();
        phone.sendSm();
        RouterProduct router = xiaomiFactory.router();
        router.openWifi();
        router.setting();
        System.out.println("==================华为系列====================");
        huaweiFactory huaweiFactory = new huaweiFactory();
        PhoneProduct phone1 = huaweiFactory.Phone();
        phone1.daphone();
        phone1.sendSm();
        RouterProduct router1 = huaweiFactory.router();
        router1.openWifi();
        router1.setting();
    }
}

输出结果:

================小米系列===================
用小米手机打电话
用小米手机发短信
小米路由器打开wifi
设置小米路由器
==================华为系列====================
用华为手机打电话
用华为手机发短信
华为路由器打开了wifi
设置华为路由器

4、建造者模式

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

主要解决:主要解决在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。

实现:

package shejimoshi.builder;
//抽象建造者
public abstract class Builder {
    abstract void builderA();
    abstract void builderB();
    abstract void builderC();
    abstract void builderD();

    abstract  Product getProduct();
}
package shejimoshi.builder;
//被建造的对象、产品
public class Product {
    private String builderA;
    private String builderB;
    private String builderC;
    private String builderD;

    public String getBuilderA() {
        return builderA;
    }

    public void setBuilderA(String builderA) {
        this.builderA = builderA;
    }

    public String getBuilderB() {
        return builderB;
    }

    public void setBuilderB(String builderB) {
        this.builderB = builderB;
    }

    public String getBuilderC() {
        return builderC;
    }

    public void setBuilderC(String builderC) {
        this.builderC = builderC;
    }

    public String getBuilderD() {
        return builderD;
    }

    public void setBuilderD(String builderD) {
        this.builderD = builderD;
    }

    @Override
    public String toString() {
        return "Product{" +
                "builderA='" + builderA + '\'' +
                ", builderB='" + builderB + '\'' +
                ", builderC='" + builderC + '\'' +
                ", builderD='" + builderD + '\'' +
                '}';
    }
}
package shejimoshi.builder;
//具体的建造者,工人
public class worker extends Builder {
    private Product product;

    public worker() {
        product=new Product();
    }

    void builderA() {
        product.setBuilderA("地基");
        System.out.println(product.getBuilderA());
    }

    void builderB() {
        product.setBuilderB("铺钢筋");
        System.out.println(product.getBuilderB());
    }

    void builderC() {
        product.setBuilderC("砌墙");
        System.out.println(product.getBuilderC());
    }

    void builderD() {
        product.setBuilderD("粉刷");
        System.out.println(product.getBuilderD());
    }

    Product getProduct() {
        return product;
    }
}
package shejimoshi.builder;
//指挥:核心,负责指挥构建一个工程,工程如何构建,由它决定
public class Dirdest {
    public Product builder(Builder builder){
        builder.builderA();
        builder.builderD();
        builder.builderB();
        builder.builderC();
        return  builder.getProduct();
    }
}
package shejimoshi.builder;

public class test {
    public static void main(String[] args) {
        Dirdest dirdest = new Dirdest();
        Product builder = dirdest.builder(new worker());
        System.out.println(builder.toString());
    }
}

第二种实现方式:

package shejimoshi.builder.demo2;
//抽象的建造者
public abstract class Builder {
    abstract Builder builderA(String msg);
    abstract Builder builderB(String msg);
    abstract Builder builderC(String msg);
    abstract Builder builderD(String msg);
    abstract Product getProduct();
}
package shejimoshi.builder.demo2;
//产品
public class Product {
    private String builderA="汉堡";
    private String builderB="炸鸡";
    private String builderC="鸡肉卷";
    private String builderD="可乐";

    public String getBuilderA() {
        return builderA;
    }

    public void setBuilderA(String builderA) {
        this.builderA = builderA;
    }

    public String getBuilderB() {
        return builderB;
    }

    public void setBuilderB(String builderB) {
        this.builderB = builderB;
    }

    public String getBuilderC() {
        return builderC;
    }

    public void setBuilderC(String builderC) {
        this.builderC = builderC;
    }

    public String getBuilderD() {
        return builderD;
    }

    public void setBuilderD(String builderD) {
        this.builderD = builderD;
    }

    @Override
    public String toString() {
        return "Product{" +
                "builderA='" + builderA + '\'' +
                ", builderB='" + builderB + '\'' +
                ", builderC='" + builderC + '\'' +
                ", builderD='" + builderD + '\'' +
                '}';
    }
}
package shejimoshi.builder.demo2;
//具体的建造者,同时兼指挥,可以改变建造事物,builderA....
public class worker extends Builder {
    private Product product;

    public worker() {
        product=new Product();
    }

    Builder builderA(String msg) {
        product.setBuilderA(msg);
        return this;
    }

    Builder builderB(String msg) {
        product.setBuilderB(msg);
        return this;
    }

    Builder builderC(String msg) {
        product.setBuilderC(msg);
        return this;
    }

    Builder builderD(String msg) {
        product.setBuilderD(msg);
        return this;
    }

    Product getProduct() {
        return product;
    }
}
package shejimoshi.builder.demo2;

public class test {
    public static void main(String[] args) {
        worker worker = new worker();
        Product product = worker.builderA("全家桶").builderD("雪碧").getProduct();
        System.out.println(product.toString());
    }
}

5、原型模式

意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象

主要解决:在运行期建立和删除原型

关键代码:利用已有的一个原型对象,快速地生成和原型对象一样的实例

实现:浅拷贝

package shejimoshi.propotry;

import java.util.Date;

public class Bilibili implements Cloneable {
    private String name;
    private Date Datetime;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public Bilibili() {
    }

    public Bilibili(String name, Date datetime) {
        this.name = name;
        Datetime = datetime;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getDatetime() {
        return Datetime;
    }

    public void setDatetime(Date datetime) {
        Datetime = datetime;
    }

    @Override
    public String toString() {
        return "Bilibili{" +
                "name='" + name + '\'' +
                ", Datetime=" + Datetime +
                '}';
    }
}
package shejimoshi.propotry;

import java.util.Date;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Date date = new Date();
        Bilibili v1 = new Bilibili("鹿鼎记", date);
        System.out.println("v1==>"+v1);
        System.out.println(v1.hashCode());
        Bilibili v2 = (Bilibili) v1.clone();
        System.out.println("v2==>"+v2);
        System.out.println(v2.hashCode());
    }
}
v1==>Bilibili{name='鹿鼎记', Datetime=Mon Nov 23 19:55:07 CST 2020}
1836019240
v2==>Bilibili{name='鹿鼎记', Datetime=Mon Nov 23 19:55:07 CST 2020}
325040804

深拷贝:

重写了clone方法,把重写后的实例也指向了date类

 @Override
    protected Object clone() throws CloneNotSupportedException {
        Bilibili o = (Bilibili) super.clone();
        o.setDatetime(new Date());
        return o ;
    }

6、适配器模式

意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

主要解决:主要解决在软件系统中,常常要将一些“现存的对象”放到新的环境中,而新环境要求的接口是现对象不能满足的。

关键代码:适配器继承或依赖已有的对象,实现想要的接口。

实现:对象适配器

package shejimoshi.adapter;
//网线
public class wangxian {
    public void Internal(){
        System.out.println("连接电脑上网");
    }
}
package shejimoshi.adapter;
//适配器接口
public interface NetInterface {
    public void NetInter();
}
package shejimoshi.adapter;
//对象适配器
public class adapter implements NetInterface {
    private wangxian w;

    public adapter(wangxian w) {
        this.w = w;
    }

    public void NetInter() {
        w.Internal();
    }
}
package shejimoshi.adapter;
//电脑及测试
public class computer {
    public void wantInternal(NetInterface netInterface){
                   netInterface.NetInter();
    }

    public static void main(String[] args) {
        computer computer = new computer();
        wangxian wangxian = new wangxian();
        adapter adapter = new adapter(wangxian);
        computer.wantInternal(adapter);
    }
}

实现二:类适配器

package shejimoshi.adapter;

public class adapter extends wangxian implements NetInterface {

    public void NetInter() {
        super.Internal();
    }
}

7、桥接模式

意图:将抽象部分与实现部分分离,使得它们都可以独立的变化。

主要解决:在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。

关键代码:抽象类依赖实现类

实现:

package shejimoshi.bridge;
//品牌接口
public interface brand {
    void info();
}
package shejimoshi.bridge;
//品牌实现类
public class Apple implements brand {
    public void info() {
        System.out.print("苹果");
    }
}
package shejimoshi.bridge;

public class lenevo implements brand {
    public void info() {
        System.out.print("联想");
    }
}
package shejimoshi.bridge;
//电脑抽象类
public abstract class computer {
    private brand brand;

    public computer(brand brand) {
        this.brand = brand;
    }

    protected void sout(){
        brand.info();
    }
}
package shejimoshi.bridge;
//抽象类的子类
public class Destkop extends computer {

    public Destkop(brand brand) {
        super(brand);
    }

    @Override
    protected void sout() {
        super.sout();
        System.out.println("台式电脑");
    }
}
package shejimoshi.bridge;

public class bijiben extends computer {
    public bijiben(shejimoshi.bridge.brand brand) {
        super(brand);
    }

    @Override
    protected void sout() {
        super.sout();
        System.out.println("笔记本");
    }
}
package shejimoshi.bridge;
//测试
public class test {
    public static void main(String[] args) {
        //苹果笔记本
        computer computer=new bijiben(new Apple());
        computer.sout();
        //联想台式电脑
        computer computer1=new Destkop(new lenevo());
        computer1.sout();
    }
}
//测试结果
苹果笔记本
联想台式电脑

8、代理模式

意图:为其他对象提供一种代理以控制对这个对象的访问

主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

关键代码:实现与被代理类组合。

8.1静态代理

package shejimoshi.proxy;
//租房接口
public interface Rent {
    void rent();
}
package shejimoshi.proxy;
//接口的实现类,房东要出租房子
public class Host implements Rent {
    public void rent() {
        System.out.println("房东要出租房子啦");
    }
}
package shejimoshi.proxy;
//代理对象,这里使用的是组合
public class Proxy {
    private Host host;

    public Proxy(Host host) {
        this.host = host;
    }
    public void rent(){
        seehome();
        host.rent();
        hetong();
    }
    public void seehome(){
        System.out.println("中介带你去看房子");
    }
    public void hetong(){
        System.out.println("要和中介签合同了");
    }
}
package shejimoshi.proxy;
//用户现实和代理对象租房子
public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }
}

8.2动态代理

关键使用proxy的newProxyInstance方法生成一个代理类,然后再调用中invocationHandler中的inovke方法实现代理类中的方法。

实例一:

package shejimoshi.proxy.demo02;

public interface Rent {
    void rent();
}
package shejimoshi.proxy.demo02;

public class Host implements Rent {
    public void rent() {
        System.out.println("房东要出租房子啦");
    }
}
package shejimoshi.proxy.demo02;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//生成代理类的invocationHandler接口的实现类
public class ProxyInvokehandler implements InvocationHandler {

    private Rent rent;

    public ProxyInvokehandler(Rent rent) {
        this.rent = rent;
    }
     public Object getProxy(){
      return  Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        seeHouse();
        System.out.println("实现了"+method.getName()+"方法");
        Object obj = method.invoke(rent);
        return obj;
    }
    public void seeHouse(){
        System.out.println("中介要带我去看房子啦");
    }
}
package shejimoshi.proxy.demo02;

public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        ProxyInvokehandler proxyInvokehandler = new ProxyInvokehandler(host);
        Rent proxy = (Rent) proxyInvokehandler.getProxy();
        proxy.rent();
    }
}

实例二:

package shejimoshi.proxy.demo03;

public interface Service {
    void add();
    void delete();
    void update();
    void query();
}
package shejimoshi.proxy.demo03;

public class ServiceImpl implements Service {
    public void add() {
        System.out.println("添加了一个用户");
    }

    public void delete() {
        System.out.println("删除了一个用户");
    }

    public void update() {
        System.out.println("修改了一个用户");
    }

    public void query() {
        System.out.println("查询了一个用户");
    }
}
package shejimoshi.proxy.demo03;

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

public class ProxyInvocationHandler implements InvocationHandler {
    private Service service;

    public void setService(Service service) {
        this.service = service;
    }
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),service.getClass().getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Log(method.getName());
        Object obj = method.invoke(service);
        return obj;
    }
    public void Log(String msg){
        System.out.println("使用了"+msg+"方法");
    }
}
package shejimoshi.proxy.demo03;

public class Client {
    public static void main(String[] args) {
        ServiceImpl service = new ServiceImpl();
        ProxyInvocationHandler handler = new ProxyInvocationHandler();
        handler.setService(service);
        Service proxy = (Service) handler.getProxy();
        proxy.query();
    }
}
posted @ 2020-11-24 13:37  小胖学java  阅读(110)  评论(0编辑  收藏  举报