Java常见几种设计模式

什么是设计模式?
设计模式是可以重复利用的解决方案。软件开发的先辈们将在开发过程中遇到的问题进行总结,并给出解决方案。后辈在遇到类似问题时,可以使用这些方案解决问题。(从设计模式可以看出,先辈们对于接口的应用。)

• 单例模式(ps:参考https://www.cnblogs.com/xiaofengwang/p/11255678.html)
一个类只有一个实例对象。这个对象的构造器被private修饰,所以不能在其他地方new,只能通过getInstance()获得实例。

单例模式的几种写法(还有其他的写法):
○ 懒汉式(加上synchronized 关键字,变成线程安全的。)

 1 public class Singleton
 2         {
 3             private static Singleton instance;
 4             private Singleton(){}
 5             public static synchronized Singleton getInstance(){
 6                 if(instance == null){
 7                     instance = new Singleton();
 8                 }
 9                 return instance;
10             }
11         }

○ 饿汉式

public class Singleton
        {
            private static Singleton instance = new Singleton();
            private Singleton(){}
            public static Singleton getInstance(){
                return instance;
            }
        }

○ 双重检验锁(不仅能够避免线程安全问题,还能防止反序列化重新创建对象。)

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

 

• 观察者模式:
观察者设计模式,定义了一种一对多的关联关系。一个对象 A 与多个对象 B、C、D 之间建立“被观察与观察关系”。当对象 A 的状态发生改变时,会通知所有观察者对象 B、 C、 D。当B、C、D 在接收到 A 的状态改变通知后,根据自身实际情况,做出相应改变。通常观察者和被观察者都是接口,上面所提到的对象是指实现了这些接口的对象。

观察者接口:

package com.bzw.observer;
    
    public interface Observer {
        //接到通知后,要做的具体处理
        void handleNotify(String message);
    }

被观察者接口:

package com.bzw.observer;
    
    public interface ToBeObservered {
    
        public void addObserver(Observer observer);
        public void removeObserver(Observer observer);
        public void notifyObserver(String message);
    }

创建观察者:

package com.bzw.observer;
    
    public class ObserverA implements Observer{
    
        @Override
        public void handleNotify(String message) {
            System.out.println(message+"A正在处理通知");
            
        }
    }
    
    package com.bzw.observer;
    
    public class ObserverB implements Observer{
    
        @Override
        public void handleNotify(String message) {
            
            System.out.println(message+"B正在处理通知");
        }
    }

创建被观察者:

package com.bzw.observer;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Observered implements ToBeObservered{
    
        List<Observer> observers = new ArrayList<>();
        @Override
        public void addObserver(Observer observer) {
            observers.add(observer);
            
        }
    
        @Override
        public void removeObserver(Observer observer) {
            observers.remove(observer);
            
        }
    
        @Override
        public void notifyObserver(String message) {
            for(Observer o : observers) {
                o.handleNotify(message);
            }
            
        }
    }

测试类:

package com.bzw.observer;
    
    public class ObserverTest {
        public static void main(String args[]) {
            ObserverA xiaowang = new ObserverA();
            ObserverB xiaoli = new ObserverB();
            Observered beauty = new Observered();
            
            beauty.addObserver(xiaowang);
            beauty.addObserver(xiaoli);
            
            beauty.notifyObserver("快来呀");
            
    //        System.out.println("----------------------");
    //        beauty.removeObserver(xiaoli);
    //        beauty.notifyObserver("再来呀");
        }
        
    }

• 装饰者模式
对某个对象功能进行拓展时,可以考虑用装饰者模式。
优点:不用修改被修饰对象的源码,装饰者与被装饰者耦合度不高。

package com.bzw.decorate;
    /**
     * 
     * 面条装饰器
     *
     */
    public interface NoodleDecorate {
        public void addThings();
    }
package com.bzw.decorate;
    public class Noodle implements NoodleDecorate{
        /**
         * 普通拉面
         */
        @Override
        public void addThings() {
            System.out.println("两片牛肉");
            System.out.println("一根胡萝卜");
            System.out.println("三根香菜");
            
        }
    }
    
package com.bzw.decorate;
    public class ChiliNoodle implements NoodleDecorate{
        
        private Noodle noodle;
        //将普通拉面对象传入
        public ChiliNoodle(Noodle noodle) {
            this.noodle = noodle;
        }
    
        @Override
        //对普通拉面进行修饰
        public void addThings() {
            noodle.addThings();
            System.out.println("加三勺辣椒");
            
        }
    }

测试类:

package com.bzw.decorate;
    public class NoodleTest {
    
        public static void main(String args[]) {
            Noodle noodle = new Noodle();
            ChiliNoodle cn = new ChiliNoodle(noodle);
            cn.addThings();
        }
    }

 

• 适配器模式(ps :参考https://www.cnblogs.com/luohanguo/p/10334291.html)
可以让原本接口不一致的类可以一起工作。有三种方式:类的适配器模式,对象适配器模式,接口适配器模式。其中对象适配器模式和接口适配器模式可以较小程度的修改源码,代码耦合度低。当不希望实现接口中的所有方法时,可以用接口适配器模式,其他情况建议用对象适配器模式。

第一种方式:

package com.bzw.adapter;
    public class Phone {
        public void typecPhone() {
            System.out.println("信息从typec口的手机输入。");
        }
    }
    
    package com.bzw.adapter;
    public interface Vga {
    
        void vgaInterface();
    }
package com.bzw.adapter;
    /*
     * 适配器第一种方式:类的适配器模式
     */
    public class TypecVga1 extends Phone implements Vga{
        
        
        @Override
        public void vgaInterface() {
            typecPhone();
            System.out.println("接收到typec口信息,转到vga接口中....");
            System.out.println("信息已转成vga,可以与显示屏对接");
        }
        
    }
    

第二种方式:
Phone类和Vga接口和方式一一样。

package com.bzw.adapter;
    /*
     * 第二种方式:对象适配器模式
     */
    public class TypecVga2 implements Vga{
    
        private Phone phone;
        
        public TypecVga2(Phone phone) {
            this.phone = phone;
        }
        @Override
        public void vgaInterface() {
            
            if(phone != null) {
                phone.typecPhone();
                System.out.println("接收到typec口信息,转到vga接口中....");
                System.out.println("信息已转成vga,可以与显示屏对接");
            }
        }
    
        
    }

测试类:

package com.bzw.adapter;
    public class Screen {
    
        public static void main(String args[]) {
            System.out.println("----------第一种方式-------------");
            TypecVga1 adapter1 = new TypecVga1();
            adapter1.vgaInterface();
            System.out.println("----------显示屏与适配器连接,手机成功投影到显示器------------");
            System.out.println("\n");
            
            System.out.println("----------第二种方式--------------");
            Phone phone = new Phone();
            TypecVga2 adapter2 = new TypecVga2(phone);
            adapter2.vgaInterface();
            System.out.println("----------显示屏与适配器连接,手机成功投影到显示器------------");
        }
    }

第三种方式:

package com.bzw.adapter.TypecVga3;
    /*
     * 第三种方式:接口的适配器模式
     */
    
    //在这个接口中可以定义多个抽象方法。
    public interface Target {
    
        public void typec();
        public void typecVga();
        public void typecHdmi();
    }
    
    package com.bzw.adapter.TypecVga3;
    //抽象类实现接口中的所有方法,这样就意味着抽象方法被实现了,子类在继承时, //可以有选择性的重写。
    public abstract class Adapter implements Target{
        
        public void typec() {};
        public void typecVga() {};
        public void typecHdmi() {};
    }
    
    package com.bzw.adapter.TypecVga3;
    public class VgaAdapter extends Adapter{
        
        public void typec() {
            System.out.println("信息从typec口的手机输入。");
        }
        public void typecVga() {
            System.out.println("接收到typec口信息,转到vga接口中....");
            System.out.println("信息已转成vga,可以与显示屏对接");
        }
        
        /**可以根据需要选择要重写的方法。
        public void typecHdmi() {
            
            System.out.println("接收到typec口信息,转到HDMI接口中....");
            System.out.println("信息已转成HDMI,可以与显示屏对接");
        }*/
        
        
    }

测试类:

package com.bzw.adapter.TypecVga3;
    
    public class Screen {
    
        public static void main(String arg[]) {
            
            System.out.println("---------第三种方式----------------");
            VgaAdapter adapter3 = new VgaAdapter();
            adapter3.typec();
            adapter3.typecVga();
            System.out.println("----------显示屏与适配器连接,手机成功投影到显示器------------");
        }
    }
    

 

• 代理模式
为一个对象提供一个代理以控制外界对该对象的访问。
○ 静态代理:代理类和相关方法直接在代码中写死。
○ 动态代理:可以直接给某一个目标对象生成一个代理对象,二不需要代理类的存在。
代理模式的优点:
○ 提高程序的扩展性和可复用性。(动态代理)
○ 保护对象。


• 工厂模式
用工厂提供的方法代替使用new创建对象的操作,将创建对象统一管理和控制从而将调用者与实现类进行解耦,实现创建者与调用者的分离。

实现工厂模式的三种方式:
○ 简单工厂模式(静态工厂):实际上它并不算是设计模式,只不过算是工厂方法和抽象工厂的基础,不过也有一些运用的地方。比如jdk的动态代理的Proxy.newProxyInstance这个就是一个简单工厂。
○ 工厂方法:工厂方法模式的实质是定义一个用于创建对象的接口,然后让实现这个接口的类来决定创建哪个类的对象。
○ 抽象工厂:抽象工厂模式提供了一种方式,可以将同一产品族的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。

对象适配器模式是其他6种结构型设计模式的起源。

三种方式总结:
○ 静态工厂 : 用来生产同一等级结构中的任意产品。产品的创建是由你传入参数决定的。
○ 工厂方法 :用来生产同一等级结构中的固定产品。一个工厂只能生产一个固定的产品。
○ 抽象工厂 :用来生产不同产品族的全部产品。一个工厂可以生产跟该产品相关的一系列产品。

posted @ 2020-10-26 23:01  晚安1024  阅读(150)  评论(0编辑  收藏  举报