offer直通车(三)之设计模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013234928/article/details/89431038

设计模式

一、设计模式分类

​ 总体来说设计模式分为三大类:

  • 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

  • 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

  • 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

1、常见的设计模式

  • 创建型模式:工厂方法模式 、 抽象工厂模式、单例模式、建造者模式 、原型模式
  • 结构型模式:适配器模式 、装饰器模式 、代理模式 、桥接模式
  • 行为型模式:命令模式、迭代器模式、策略模式、观察者模式

2、JDK中的体现

工厂方法模式

单列模式:Runtime;

抽象工厂模式:Calendar

适配器模式:IO 转换流(InputStreamReader、OutputStreamWriter )

装饰器模式:IO 流

策略模式:java.util.Comparator#compare() 、javax.servlet.http.HttpServlet 、javax.servlet.Filter#doFilter()

建造者模式:StringBuilder


二、六大原则

  1. 开闭原则:对扩展开发放,对修改关闭,抽象化是开闭原则的关键
  2. 单一职责原则:尽量使用合成/聚合的方式,而不是使用继承。一个类只负责一个功能领域中的相应职责
  3. 里式替换原则 :任何基类可以出现的地方,子类一定可以出现。
  4. 依赖倒转原则:依赖于抽象而不依赖于具体
  5. 接口隔离原则:使用多个隔离的接口,比使用单个接口要好 ,即客户端不应该依赖那些它不需要的接口。
  6. 迪米特法则:一个软件实体应当尽可能少地与其他实体发生相互作用。

设计详解

一、工厂模式(常见)

工厂模式可以分为三类:

1)简单工厂模式(Simple Factory):对象有个公共的接口 --> 不是23种类型中的一种

2)工厂方法模式(Factory Method) :有一个工厂类,通过判读创建不同的对象

​ JDK体现:java.lang.Integer#valueOf(String) (Boolean, Byte, Character,Short, Long, Float 和 Double与之类似)

3)抽象工厂模式(Abstract Factory):有个公共的抽象的工厂类,每个子类创建不同类型的对象

1、工厂方法模式

2、抽象工厂模式


二、单例模式(常见)

常见单例:懒汉式、饿汉式、登记式、枚举式(后三种天生线程安全)。

推荐使用饿汉式,明确实现lazy loading的效果,则使用登记方式;涉及反序列化使用枚举式,特殊条件可以考虑双检锁方式

jdk 体现:java.lang.Runtime#getRuntime()

1、单例模式特点

  • 单例类只能有一个实例。
  • 单例类必须自己创建自己的唯一实例。
  • 单例类必须给所有其他对象提供这一实例。

优点:

  • 在内存中只有一个对象,节省内存空间;
  • 避免频繁的创建销毁对象,可以提高性能;
  • 避免对共享资源的多重占用,简化访问;
  • 为整个系统提供一个全局访问点

饿汉式和懒汉式区别

  • 饿汉式:天生就是线程安全的,立即加载, 执行效率提高;容易产生垃圾对象

  • 懒汉式:本身是非线程安全的,延迟加载;调用才初始化,避免内存浪费


扩展:

注意: 立即加载 和延迟加载

  • 立即加载 : 在类加载初始化的时候就主动创建实例;
  • 延迟加载 : 等到真正使用的时候才去创建实例,不用时不去

2、懒汉式单例

​ 优缺点:延迟加载:调用才初始化,避免内存浪费,但不支持多线程

1> 不安全懒汉式

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

懒汉式加synchronized 修饰,可以用于多线程

2> 安全型懒汉式

优缺点:可用于多线程,传说效率低,99%的情况不需要同步

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

3> 双检锁懒汉式

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;  
    }  
}

3、饿汉式单例

天生具体安全性,容易产生垃圾对象,属于立即加载

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

4、登记式/静态内部类

public class Singleton {  
    private static class SingletonHolder {  
    	private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
    	return SingletonHolder.INSTANCE;  
    }  
}

5、枚举

实现单例模式的最佳方法;天生具体安全性

class Resource{
}

public enum Singleton {
    INSTANCE;
    private Resource instance;
    Singleton() {
        instance = new Resource();
    }
    public Resource getInstance() {
        return instance;
    }
}

三、建造者模式(常见)

  • 使用多个简单的对象一步一步构建成一个复杂的对象
  • 如: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"
  • JDK中的体现:StringBuilder

四、原型模式(常见)

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

利用java克隆技术继承Cloneable重写clone、或者序列化和反序列化

浅拷贝:Object类的clone方法指对拷贝对象的基本类型,对数组,容器对象,引用对象等不会拷贝;

深拷贝:如果实现深拷贝,必须将原型模式中的数组,容器对象,引用对象等另行拷贝


五、适配器模式(常见)

定义:将两个原来不兼容的类兼容起来一起工作。

  • **JDK中的体现:**IO流中的转换流;如:InputStreamReader、Arrays.asList()
  • 例子:苹果手机电源转换插头

六、装饰器模式(常见)

定义:装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构

  • **JDK中的体现:**IO流 中的不同类型的流,InputStream、OutputStream、

  • 配一台台式电脑,配件有显示器,键盘、鼠标等,又有不同的品牌,则有:一个配件基类Components(定义了配件描述属性和输出描述的方法)、一个品牌基类Brand继承Components,配件基类有键盘和鼠标2个实现类,品牌基类有华为和联想2个实现类

//配件基类Components
public abstract class Compoments{
    public String desc;
    public abstract String getDesc();
}
//键盘
public class keyBoard extends Compoments{
    public keyBoard(){
        desc="键盘";
    }
    @Override
    public  String getDesc(){
        return  desc;
    }
}
//鼠标
public class Mouse extends Compoments{
    public Mouse(){
        desc="键盘";
    }
    @Override
    public  String getDesc(){
        return  desc;
    }
}

----------------------------------------
//基类Brand
public abstract class Brand extends Compoments{
    @Override
    public abstract String getDesc();
}
//huwei
public class Huawei extends Brand{
    private Compoments compoments;
    private String brand = "Huawei";
    public Huawei(Compoments p){
        this.compoments=p;
    }
    @Override
    public  String getDesc(){
        return  brand+compoments.desc;
    }
}
//acer
public class Acer extends Brand{
    private Compoments compoments;
    private String brand = "Acer";
    public Acer(Compoments p){
        this.compoments=p;
    }
    @Override
    public  String getDesc(){
        return  brand+compoments.desc;
    }
} 
------------
//操作类
Compoments compoments = null;
//不要配件只要裸机
compoments = new keyBoard(); 
System.out.println(compoments.getDesc());    

//----------------
compoments = new Acer(compoments); 
System.out.println(compoments.getDesc()); 
    
    

优点:

  • 装饰类和被装饰类可以独立发展
  • 无耦合
  • 装饰模式是继承的一个替代模式
  • 装饰模式可以动态扩展一个实现类的功能。

缺点:多层装饰比较复杂


七、代理模式(常见)

定义:将原类进行封装,为其他对象提供一个代理,以控制对当前对象的访问。

  • 静态代理:被代理对象与代理对象一起实现相同的接口或者是继承相同父类.
  • jdk动态代理:java.lang.reflect.Proxy.newProxyInstance() 和InvocationHandler对象
  • cglib动态代理:实现MethodInterceptor 接口
/**
 * 静态代理
 */
public interface HelloService {
    String hello(String name);
}
public class HelloServiceImpl implements HelloService{
    @Override
    public String hello(String name) {
        return "Hello " + name;
    }
}
//代理类
public class HelloServiceProxy implements HelloService {
    private HelloService helloService;
    public HelloServiceProxy(HelloService helloService) {
        this.helloService = helloService;
    }

    @Override
    public String hello(String name) {
        System.out.println("预处理...");
        String result = helloService.hello(name);
        System.out.println(result);
        System.out.println("后处理...");
        return result;
    }
}
//测试
HelloService helloService = new HelloServiceImpl();
HelloServiceProxy helloServiceProxy = new HelloServiceProxy(helloService);
helloServiceProxy.hello("Panda");
//-------------------------------------------------------------------
/**
 * 创建JDK动态代理对象
 * 动态代理不需要实现接口,但是需要指定接口类型
 */
public class ProxyFactory{

    //维护一个目标对象
    private Object target;
    public ProxyFactory(Object target){
        this.target=target;
    }

   //给目标对象生成代理对象
    public Object getProxyInstance(){
        return Proxy.newProxyInstance( target.getClass().getClassLoader(),  target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("开始事务2");
                        //执行目标对象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("提交事务2");
                        return returnValue;
                    }
                }
        );
    }

}


/**
 * Cglib子类代理工厂
 * 对UserDao在内存中动态构建一个子类对象
 */
public class ProxyFactory implements MethodInterceptor{
    //维护目标对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();

    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("开始事务...");

        //执行目标对象的方法
        Object returnValue = method.invoke(target, args);

        System.out.println("提交事务...");

        return returnValue;
    }
}

八、外观模式

  • 定义:隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口
  • 构造方法中创建一个接口的所有子对象,并提供方法来访问子对象中的方法
  • jdk 中的体现:Class

九、桥接模式

十、组合模式

十一、享元模式

  • 享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。

  • String常量池、数据库连接池、缓冲池等等都是享元模式的应用,所以说享元模式是池技术的重要实现方式

  • java对于Integer与int的自动装箱与拆箱的设计,是一种模式:叫享元模式(flyweight)

  • **如何解决:**用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象。

    **关键代码:**工厂类中用 HashMap 存储这些对象。

import java.util.HashMap;
 
public class ShapeFactory {
   private static final HashMap<String, Shape> circleMap = new HashMap<>();
 
   public static Shape getCircle(String color) {
      Circle circle = (Circle)circleMap.get(color);
 
      if(circle == null) {
         circle = new Circle(color);
         circleMap.put(color, circle);
         System.out.println("Creating circle of color : " + color);
      }
      return circle;
   }
}

十二、策略模式(常见)

  • 定义:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。

  • **JDK中的体现:**ThreadPoolExecutor(提供了四种策略)

  • 策略模式和工厂方法模式,有点像,工厂方法模式是关注对象的创建,策略模式是关注行为的封装


十三、模板方法模式


十四、观察者模式(常见)

定义:定义对象间的一种一对多的依赖关系;当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。

关键点:在抽象类里有一个 ArrayList 存放观察者们。

例子:拍卖师(Auction)每次宣布一件物品(goods)开始竞拍,竞价者(Bidder)听到指令开始竞价

public class Auction{
    private String goods;
    private ListArray<Bidder> bidders= new ArrayList<Bidder>();
    public void setGoods(String goods){
    	this.goods=goods; 
        notifyAllBidder();
    }
    public String getGoods(){
    	return goods;
    }
    public void attach(Bidder b){
      bidders.add(b);      
   }
 
   public void notifyAllBidder(){
      for (Bidder b : bidders) {
         b.update();
      }
   }  
}

public abstract class Bidder {
   protected Auction auction;
   public abstract void update();
}
//路人A Aperson
public class ApersonBidder extends Bidder{
 
   public ApersonBidder(Auction a){
      this.auction = a;
      this.auction.attach(this);
   }
 
   @Override
   public void update() {
      System.out.println(this.auction.getGoods() + "--A出价10万 "); 
   }
}

//路人B Bperson
public class BpersonBidder extends Bidder{
 
   public BpersonBidder(Auction a){
      this.auction = a;
      this.auction.attach(this);
   }
 
   @Override
   public void update() {
      System.out.println( this.auction.getGoods() + "--B出价30万 "); 
   }
}

//操作类
Auction auction = new Auction();
 
new ApersonBidder(auction);
new BpersonBidder(auction);
 
subject.setState("瓷器");
subject.setState("字画");

十五、迭代子模式

十六、责任链模式

十七、命令模式

十八、备忘录模式

十九、状态模式

二十、访问者模式

二十一、中介者模式

定义: 定义一个中介对象来封装系列对象之间的交互

例子:中介公司

二十二、解释器模式

猜你喜欢

转载自blog.csdn.net/u013234928/article/details/89431038