设计模式——单例模式、工厂模式、代理模式、观察者模式、装饰器模式

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

什么是设计模式

设计模式是一种解决方案,用于解决在软件设计中普遍存在的问题,是前辈们对之前软件设计中反复出现的问题的一个总结。
至于我们为什么要学习设计模式,我觉得轮子哥总结的很好

我们学设计模式,是为了学习如何合理的组织我们的代码,如何解耦,如何真正的达到对修改封闭对扩展开放的效果,而不是去背诵那些类的继承模式,然后自己记不住,回过头来就骂设计模式把你的代码搞复杂了,要反设计模式。

设计模式六要素

单一职责原则(Single Responsibility Principle, SRP)

一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。

单一职责原则要求一个类不能承担过多的职责,形成“超级类”。需要根据不同职责分为不同的类,从而降低类的复杂度,提升其可读性,增加系统的稳定性。

开闭原则(Open-Closed Principle, OCP)

一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。

很多需求都会随着时间变化而发生变化,因此当功能需要拓展时,应当能够很方便的进行拓展,且在拓展时不影响现有代码。

里氏代换原则(Liskov Substitution Principle, LSP)

所有引用基类(父类)的地方必须能透明地使用其子类的对象。

里氏代换原则要求在软件中一个基类能够替换为它的子类而不会因此任何异常。因此要求子类可以扩展父类的功能,但不能修改父类本身的非抽象方法。

依赖倒置原则(Dependency Inversion Principle, DIP)

抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。

依赖倒置原则要求我们在程序代码中尽量引用层次高的抽象层类。因此我们需要针对抽象层编程,将具体类通过依赖注入的方式注入到其他对象中。
在大多数情况下,开闭原则、里氏代换原则和依赖倒置原则会同时出现,开闭原则是目标,里氏代换原则是基础,依赖倒置原则是手段。

接口隔离原则(Interface Segregation Principle, ISP)

使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

接口隔离原则要求我们设计接口不应太大,接口应仅仅提供客户端需要的行为。
在使用此原则时应注意接口的粒度,接口太小会导致接口泛滥,不利于维护,接口太大灵活性较差,使用不便。

迪米特法则(Law of Demeter, LoD)

一个软件实体应当尽可能少地与其他实体发生相互作用。

迪米特法则要求我们应该减少对象之间的交互,如果两个对象之间不必彼此之间直接通信,那么这两个对象就不应该发送任何直接的相互作用,当需要调用另一个对象的某一方法时,可以通过第三者来转发此调用。

常见模式

单例模式(Singleton Pattern)【创建型模式】

  • 作用
    用于保证一个类有且仅有一个实例,用来解决一个全局使用的类频繁的创建和销毁,从而节约系统资源。
  • 懒汉型,线程不安全
    此方法线程不安全,因此在严格意义上来说不能算作单例模式。
public callss singleton {
    private static Singleton instance;
    private Singletone(){}
    public static singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }

}
  • 懒汉型,线程安全
    该方法通过synchronized关键字保证线程安全,但效率会有所降低。
public class Singleton {
    private static Singleton instance;
    private Singleton(){}
    public static synchronized Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}
  • 饿汉型
    饿汉型没有使用Synchronize关键字,因而效率较高,但是没有达到lazy loading的效果。
public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton(){}
    public static Singleton getInstance() {
        return instance;
    }
}
  • 双检锁/双重检验锁
    双锁机制保证了线程安全且在大多数情况下保持高性能,达到了lazy loading效果。
public class Singleton {
   private volatile static Singleton singleton;
   private Singleton(){}
   public static Singleton getSingleton() {
       if (singleton == null) {
           synchronized (Singleton.class){
               singleton = new Singleton();
           }
       }
       return singleton;
   }

}
  • 静态内部类
public class Singleton {
    private static class SingletonHolder {
    private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton(){}
    public static final Singleton getInstance() {
      return SingletonHolder.INSTANCE;
    }
}
  • 枚举
pubilc enum Singleton{
    INSTANCE;
    public void whateverMethod(){
    }
}

工厂模式(Factory Pattern)【创建型模式】

  • 作用
    用于创建复制对象,明确地计划不同条件下创建不同的实例。
  • 优点
    使代码结构清晰,能够更加有效的进行封装。对调用者屏蔽具体的产品实现。降低耦合度。
  • 缺点
    对于简单对象,使用工厂模式会增加其系统的复杂度。
//产品类接口
interface IProduct {  
    public void productMethod();  
}  

//产品类实体
class Product implements IProduct {  
    public void productMethod() {  
        System.out.println("产品");  
    }  
}  

//工厂类接口
interface IFactory {  
    public IProduct createProduct();  
}  

//工厂类实体
class Factory implements IFactory {  
    public IProduct createProduct() {  
        return new Product();  
    }  
}  

//用户
public class Client {  
    public static void main(String[] args) {  
        IFactory factory = new Factory();  
        IProduct prodect = factory.createProduct();  
        prodect.productMethod();  
    }  
}  

代理模式(Proxy Pattern)【结构型模式】

  • 作用
    为其他对象提供一种代理来控制对某个对象的访问,在一些已有的方法在使用的时候需要对已有的方法进行拓展,可用此模式来完成。
  • 优点
    职责清晰,有更高的拓展性,更加的智能。
  • 缺点
    实现代理模式增加了工作量,且通过代理模式访问会使性能降低。
//源对象接口
public interface Sourceable {  
    public void method();  
}

//源对象实现类
public class Source implements Sourceable {  

    @Override  
    public void method() {  
        System.out.println("the original method!");  
    }  
}

//代理类
public class Proxy implements Sourceable {  

    private Source source;  
    public Proxy(){
        this.source = new Source();  
    }

    @Override  
    public void method() {  
        if (source == null){
            source = new Source ();
        } 
        source.method();  
    }   
}  

装饰器模式(Decorator Pattern)【结构型模式】

  • 作用
    通过一个更加灵活的方式动态的为某一个对象添加一些额外的职责
  • 优点
    可以再不添加很多子类的情况下拓展类,且装饰类和被装饰类可以独立方法。
  • 缺点
    多层装饰较为复杂
//需被拓展的类的接口
public interface Shape {
   void draw();
}

//需被拓展的类
public class Rectangle implements Shape {
   @Override
   public void draw() {
      System.out.println("Shape: Rectangle");
   }
}

//创建实现了 Shape 接口的抽象装饰类。
public abstract class ShapeDecorator implements Shape {
   protected Shape decoratedShape;

   public ShapeDecorator(Shape decoratedShape){
      this.decoratedShape = decoratedShape;
   }

   public void draw(){
      decoratedShape.draw();
   }    
}

//扩展了 ShapeDecorator 类的实体装饰类
public class RedShapeDecorator extends ShapeDecorator {
   public RedShapeDecorator(Shape decoratedShape) {
      super(decoratedShape);        
   }

   @Override
   public void draw() {
      decoratedShape.draw();           
      setRedBorder(decoratedShape);
   }

   private void setRedBorder(Shape decoratedShape){
      System.out.println("Border Color: Red");
   }
}

观察者模式(Observer Pattern)【行为型模式】

  • 作用
    用于在易用和低耦合下实现一个对象改变给其他对象通知的功能。
  • 优点
    观察者和被观察抽象耦合的。
    • 缺点
      当观察者较多时,完成通知耗时较长,观察者和被观察是循环依赖时,会导致循环调用,可能会使导致系统崩溃
//创建被观察者
public class Subject {

   private List<Observer> observers 
      = new ArrayList<Observer>();
   private int state;

   public int getState() {
      return state;
   }

   public void setState(int state) {
      this.state = state;
      notifyAllObservers();
   }

   public void attach(Observer observer){
      observers.add(observer);      
   }

  public void notifyAllObservers(){
      for (Observer observer : observers) {
         observer.update();
      }
   }

//创建观察者抽象类
public abstract class Observer {
   protected Subject subject;
   public abstract void update();
}

//观察者实现类1
public class BinaryObserver extends Observer{

   public BinaryObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }

   @Override
   public void update() {
      System.out.println( "Binary String: " 
      + Integer.toBinaryString( subject.getState() ) ); 
   }
}

//观察者实现类2
public class OctalObserver extends Observer{

   public OctalObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }

   @Override
   public void update() {
     System.out.println( "Octal String: " 
     + Integer.toOctalString( subject.getState() ) ); 
   }
}

//改变被观察者状态
public class ObserverPatternDemo {
   public static void main(String[] args) {
      Subject subject = new Subject();

      new OctalObserver(subject);
      new BinaryObserver(subject);

      System.out.println("First state change: 15"); 
      subject.setState(15);
      System.out.println("Second state change: 10");    
      subject.setState(10);
   }
}

参考文档

为什么我们需要学习(设计)模式 —— vczh
设计模式之六大原则(转载) —— 海子
设计模式|菜鸟教程

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页