后端学习 - 设计模式与设计原则

文章目录

  • 设计原则
    • 1 单一职责原则
    • 2 开闭原则
    • 3 Liskov 替换原则
    • 4 依赖倒置原则
    • 5 接口隔离原则
    • 6 迪米特法则
  • 设计模式:创建型模式
    • 1 工厂模式
    • 2 抽象工厂模式
    • 3 单例模式
  • 设计模式:行为型模式
    • 1 观察者模式
    • 2 模板模式
    • 3 备忘录模式
  • 设计模式:结构型模式
    • 1 代理模式
    • 2 装饰器模式
    • 3 适配器模式

设计原则

六大设计原则详解

1 单一职责原则

  • 一个类只专注于做一件事

2 开闭原则

  • 开闭原则是 OOP 中最基础的设计原则
  • 对拓展开放,对修改关闭,尽可能在不改变原有代码的情况下进行拓展
  • 要实现开闭原则,首先实现面向接口编程(依赖倒置原则)

3 Liskov 替换原则

  • 子类必须能够替换它们的基类型
  • “父类能做的事,子类必须能做,要做到相等或更好”

4 依赖倒置原则

  • 核心思想是面向接口编程,依赖于抽象而不依赖于具体
  • 写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互
  • 使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类完成

5 接口隔离原则

  • 使用多个隔离的接口,比使用单个臃肿庞大接口要好(尽量细化接口,接口中的方法尽量少)
  • 如果接口过于臃肿,只要接口中出现的方法,不管对依赖于它的类有没有用处,实现类中都必须去实现这些方法

6 迪米特法则

  • 一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立

设计模式:创建型模式

1 工厂模式

  • 主要解决接口选择的问题:将同一类对象的创建过程,转移到一个工厂类实现
  • 在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象
    后端学习 - 设计模式与设计原则_第1张图片
// 1.创建接口
public interface Shape {
   void draw();
}


// 2.创建接口的实现类
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.");
   }
}


// 3.创建工厂
public class ShapeFactory {

   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();
	  
	  //...
   }
}

2 抽象工厂模式

  • 生产工厂的工厂,将属于同一类型的工厂聚合在一起
  • 从工厂生产器中获取的工厂,也用共用的接口指向同一对象
    后端学习 - 设计模式与设计原则_第2张图片
// 1.创建形状和颜色的接口,及其实现类(略)


// 2.设置形状和颜色的抽象工厂
public abstract class AbstractFactory {
   public abstract Color getColor(String color);
   public abstract Shape getShape(String shape);
}


// 3.继承抽象工厂,实现各自对应的方法
public class ShapeFactory extends AbstractFactory {
   @Override
   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;
   }
   
   @Override
   public Color getColor(String color) {
      return null;
   }
}

public class ColorFactory extends AbstractFactory {
    
   @Override
   public Shape getShape(String shapeType){
      return null;
   }
   
   @Override
   public Color getColor(String color) {
      if(color == null){
         return null;
      }        
      if(color.equalsIgnoreCase("RED")){
         return new Red();
      } else if(color.equalsIgnoreCase("GREEN")){
         return new Green();
      } else if(color.equalsIgnoreCase("BLUE")){
         return new Blue();
      }
      return null;
   }
}


// 4.工厂生产器——工厂的工厂
public class FactoryProducer {
   public static AbstractFactory getFactory(String choice){
      if(choice.equalsIgnoreCase("SHAPE")){
         return new ShapeFactory();
      } else if(choice.equalsIgnoreCase("COLOR")){
         return new ColorFactory();
      }
      return null;
   }
}
public class AbstractFactoryPatternDemo {
   public static void main(String[] args) {
   
      //获取形状工厂
      AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
 
      //获取形状为 Circle 的对象
      Shape shape1 = shapeFactory.getShape("CIRCLE");
 
      //调用 Circle 的 draw 方法
      shape1.draw();
 
      //获取颜色工厂
      AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
 
      //获取颜色为 Red 的对象
      Color color1 = colorFactory.getColor("RED");
 
      //调用 Red 的 fill 方法
      color1.fill();
   }
}

3 单例模式

  • 一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建

  • 可以直接访问,不需要实例化该类的对象

  • 最常用的 DCL (double-checked locking) 实现:
    构造方法使用 private 修饰,保证该类只有自己能实例化自己
    使用 volatile 修饰属性,指示 JVM,变量是共享且不稳定的,每次使用它都到主存中进行读取,并禁止指令重排

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

设计模式:行为型模式

1 观察者模式

  • 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
// 1.被观察者类
public class Subject {
   private List<Observer> observers = new ArrayList<Observer>();  // 用List存放所有观察者
   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();
      }
   }
}


// 2.观察者抽象类及其实现
public abstract class Observer {
   protected Subject subject;
   public abstract void update();
}

public class BinaryObserver extends Observer{
 
   public BinaryObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);  // 调用被观察者的attch方法,将自己注册为它的观察者
   }
 
   @Override
   public void update() {
      System.out.println( "Binary String: " 
      + Integer.toBinaryString( subject.getState() ) ); 
   }
}
......
public class ObserverPatternDemo {
   public static void main(String[] args) {
      Subject subject = new Subject();
 
      new HexaObserver(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);
   }
}

2 模板模式

  • 一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行
  • 模板方法被声明为 final,因为执行它的流程是固定的
// 1.模板类
public abstract class Game {
   abstract void initialize();
   abstract void startPlay();
   abstract void endPlay();
 
   // 模板方法,它规定了其他方法的执行流程是固定的
   public final void play(){
      //初始化游戏
      initialize();
      //开始游戏
      startPlay();
      //结束游戏
      endPlay();
   }
}


// 2.模板类的不同实现
public class Football extends Game {
   @Override
   void endPlay() {
      System.out.println("Football Game Finished!");
   }
   @Override
   void initialize() {
      System.out.println("Football Game Initialized! Start playing.");
   }
   @Override
   void startPlay() {
      System.out.println("Football Game Started. Enjoy the game!");
   }
}

public class Cricket extends Game {
   @Override
   void endPlay() {
      System.out.println("Cricket Game Finished!");
   }
   @Override
   void initialize() {
      System.out.println("Cricket Game Initialized! Start playing.");
   }
   @Override
   void startPlay() {
      System.out.println("Cricket Game Started. Enjoy the game!");
   }
}
public class TemplatePatternDemo {
   public static void main(String[] args) {
 	  // 不同的实现使用相同的模板
      Game game = new Cricket();
      game.play();
      game = new Football();
      game.play();      
   }
}

3 备忘录模式

  • 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态
  • 备忘录模式使用三个类 MementoOriginatorCareTaker
    Memento 包含了要被恢复的对象的状态,相当于每一个存档;
    Originator 创建并在 Memento 对象中存储状态,是要被存储的对象;
    Caretaker 对象负责从 Memento 中恢复对象的状态,相当于存档的集合
// 1.Memento 类,包含了要被恢复的对象的状态
public class Memento {
   private String state;
 
   public Memento(String state){
      this.state = state;
   }
 
   public String getState(){
      return state;
   }  
}


// 2.Originator 类,要被记录的类
public class Originator {
   private String state;
 
   public void setState(String state){
      this.state = state;
   }
 
   public String getState(){
      return state;
   }
 
   public Memento saveStateToMemento(){
      return new Memento(state);
   }
 
   public void getStateFromMemento(Memento Memento){
      state = Memento.getState();
   }
}


// 3.CareTaker 类,负责从 Memento 中恢复对象的状态
public class CareTaker {
   private List<Memento> mementoList = new ArrayList<Memento>();
 
   public void add(Memento state){
      mementoList.add(state);
   }
 
   public Memento get(int index){
      return mementoList.get(index);
   }
}
public class MementoPatternDemo {
   public static void main(String[] args) {
      Originator originator = new Originator();
      CareTaker careTaker = new CareTaker();
      originator.setState("State #1");
      originator.setState("State #2");
      careTaker.add(originator.saveStateToMemento());
      originator.setState("State #3");
      careTaker.add(originator.saveStateToMemento());
      originator.setState("State #4");
 
      System.out.println("Current State: " + originator.getState());    
      originator.getStateFromMemento(careTaker.get(0));
      System.out.println("First saved State: " + originator.getState());
      originator.getStateFromMemento(careTaker.get(1));
      System.out.println("Second saved State: " + originator.getState());
   }
}

Current State: State #4
First saved State: State #2
Second saved State: State #3

设计模式:结构型模式

1 代理模式

  • 直接访问会给使用者或者系统结构带来很多麻烦时,为其他对象提供一种代理以控制对这个对象的访问
  • 示例:图像首次显示时需要先加载,再次访问不需要;通过代理自动化地完成这一过程

后端学习 - 设计模式与设计原则_第3张图片

// 1.创建接口及其实现类
public interface Image {
   void display();
}

public class RealImage implements Image {

   private String fileName;
 
   public RealImage(String fileName){
      this.fileName = fileName;
      loadFromDisk(fileName);
   }
 
   @Override
   public void display() {
      System.out.println("Displaying " + fileName);
   }
 
   private void loadFromDisk(String fileName){
      System.out.println("Loading " + fileName);
   }
}


// 2.创建代理
public class ProxyImage implements Image {
 
   private RealImage realImage;
   private String fileName;
 
   public ProxyImage(String fileName){
      this.fileName = fileName;
   }
 
   @Override
   public void display() {  // 代理的功能
      if(realImage == null){
         realImage = new RealImage(fileName);
      }
      realImage.display();
   }
}
public class ProxyPatternDemo {
   
   public static void main(String[] args) {
      Image image = new ProxyImage("test_10mb.jpg");
      // 图像将从磁盘加载
      image.display(); 
      // 图像不需要从磁盘加载
      image.display();  
   }
}

2 装饰器模式

  • 动态地给一个对象添加一些额外的职责,将其包装成功能更强大的类,效果类似于继承,作为继承的一种替代方式
  • 就增加功能来说,装饰器模式相比生成子类更为灵活
// 1.创建形状接口及其实现类
public interface Shape {
   void draw();
}

public class Rectangle implements Shape {
   @Override
   public void draw() {
      System.out.println("Shape: Rectangle");
   }
}


// 2.抽象装饰类及其实现
public abstract class ShapeDecorator implements Shape {
   protected Shape decoratedShape;
 
   public ShapeDecorator(Shape decoratedShape){
      this.decoratedShape = decoratedShape;
   }
 
   public void draw(){
      decoratedShape.draw();
   }  
}

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");
   }
}
public class DecoratorPatternDemo {
   public static void main(String[] args) {
 
      Shape circle = new Circle();
      ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
      ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());
      //Shape redCircle = new RedShapeDecorator(new Circle());
      //Shape redRectangle = new RedShapeDecorator(new Rectangle());
      System.out.println("Circle with normal border");
      circle.draw();
 
      System.out.println("\nCircle of red border");
      redCircle.draw();
 
      System.out.println("\nRectangle of red border");
      redRectangle.draw();
   }
}

3 适配器模式

  • 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁,结合了两个独立接口的功能
// 1.创建要捏合的两个接口
public interface MediaPlayer {
   public void play(String audioType, String fileName);
}

public interface AdvancedMediaPlayer { 
   public void playVlc(String fileName);
   public void playMp4(String fileName);
}


// 2.创建加强播放器的实现类
public class VlcPlayer implements AdvancedMediaPlayer{
   @Override
   public void playVlc(String fileName) {
      System.out.println("Playing vlc file. Name: "+ fileName);      
   }
 
   @Override
   public void playMp4(String fileName) {
      //什么也不做
   }
}

public class Mp4Player implements AdvancedMediaPlayer{
   @Override
   public void playVlc(String fileName) {
      //什么也不做
   }
 
   @Override
   public void playMp4(String fileName) {
      System.out.println("Playing mp4 file. Name: "+ fileName);      
   }
}


// 3.创建 实现加强播放器方法的 适配器类
public class MediaAdapter implements MediaPlayer {
 
   AdvancedMediaPlayer advancedMusicPlayer;
 
   public MediaAdapter(String audioType){
      if(audioType.equalsIgnoreCase("vlc") ){
         advancedMusicPlayer = new VlcPlayer();       
      } else if (audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer = new Mp4Player();
      }  
   }
 
   @Override
   public void play(String audioType, String fileName) {
      if(audioType.equalsIgnoreCase("vlc")){
         advancedMusicPlayer.playVlc(fileName);
      }else if(audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer.playMp4(fileName);
      }
   }
}


// 4.创建未增强的播放器,注入适配器
public class AudioPlayer implements MediaPlayer {
   MediaAdapter mediaAdapter; 
 
   @Override
   public void play(String audioType, String fileName) {    
 
      //播放 mp3 音乐文件的内置支持
      if(audioType.equalsIgnoreCase("mp3")){
         System.out.println("Playing mp3 file. Name: "+ fileName);         
      } 
      //mediaAdapter 提供了播放其他文件格式的支持
      else if(audioType.equalsIgnoreCase("vlc") 
         || audioType.equalsIgnoreCase("mp4")){
         mediaAdapter = new MediaAdapter(audioType);
         mediaAdapter.play(audioType, fileName);
      }
      else{
         System.out.println("Invalid media. "+
            audioType + " format not supported");
      }
   }   
}
public class AdapterPatternDemo {
   public static void main(String[] args) {
      AudioPlayer audioPlayer = new AudioPlayer();
 
      audioPlayer.play("mp3", "beyond the horizon.mp3");
      audioPlayer.play("mp4", "alone.mp4");
      audioPlayer.play("vlc", "far far away.vlc");
   }
}

你可能感兴趣的:(Java开发,java)