美文网首页
【常用设计模式】观察者-模板-策略-责任链-适配器-代理-装饰器

【常用设计模式】观察者-模板-策略-责任链-适配器-代理-装饰器

作者: 植富宝 | 来源:发表于2019-02-28 12:05 被阅读0次

    ==目录==

    ==前言==

    1. 设计模式分类

    创建型模式:用来构建对象以便能从实现系统解耦
    结构型模式:用不同的对象组成大规模的对象结构
    行为型模式:用来在对象中管理算法、关系、责任
    
    对象层面:处理对象之间的关系,决定于运行期
    类层面:处理类的关系,决定于在编译器
    

    2. 设计模式六大原则

    1-开闭原则:
        对扩展开放,对修改关闭。
        就是代码需要扩展的时候,不需要修改原有的代码。
        而实现开闭原则的关键步骤就是抽象化。
        
    2-里氏代换原则:
        是对开闭原则的补充。
        对实现抽象化的具体步骤的规范。
        
    3-依赖倒转原则:
        是开闭原则的基础。
        针对接口编程,依赖抽象而不是具体。
        
    4-接口隔离原则:
        使用多个隔离的接口,比使用单个接口要好。
        降低类之间的耦合度。
        
    5-最小知识原则:
        一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立
        
    6-合成/聚合复用原则:
        尽量使用合成/聚合的方式,而不是使用继承
        
    面向对象原则:
        对接口编程而不是对实现编程。
        优先使用对象组合而不是继承。
    

    ==1-行为型==

    ==1-观察者模式-行为型==

    image
    优点: 
    1、观察者和被观察者是抽象耦合的。 
    2、建立一套触发机制。
    
    缺点: 
    1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 
    2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 
    3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
    
    使用场景:
    1、一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
    2、一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
    3、一个对象必须通知其他对象,而并不知道这些对象是谁。
    4、需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
    
    1. 创建主题
    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();
          }
       }  
    }
    
    2. 创建观察者抽象类
    public abstract class Observer {
       protected Subject subject;
       public abstract void update();
    }
    
    3. 创建实体观察者类
    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() ) ); 
       }
    }
    
    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 HexaObserver extends Observer{
     
       public HexaObserver(Subject subject){
          this.subject = subject;
          this.subject.attach(this);
       }
     
       @Override
       public void update() {
          System.out.println( "Hex String: " 
          + Integer.toHexString( subject.getState() ).toUpperCase() ); 
       }
    }
    
    4. 应用
    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);
       }
    }
    
    5. 执行程序,输出结果:
    First state change: 15
    Hex String: F
    Octal String: 17
    Binary String: 1111
    Second state change: 10
    Hex String: A
    Octal String: 12
    Binary String: 1010
    

    ==2-模板模式-行为型==

    模板
    优点: 
    1、封装不变部分,扩展可变部分。 
    2、提取公共代码,便于维护。 
    3、行为由父类控制,子类实现。
    
    缺点:
    每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
    
    使用场景: 
    1、有多个子类共有的方法,且逻辑相同。 
    2、重要的、复杂的方法,可以考虑作为模板方法。
    
    1. 创建模板抽象类
    public abstract class Game {
       abstract void initialize();
       abstract void startPlay();
       abstract void endPlay();
       //模板
       public final void play(){
          //初始化游戏
          initialize();
          //开始游戏
          startPlay();
          //结束游戏
          endPlay();
       }
    }
    
    2. 继承模板抽象类
    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 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!");
       }
    }
    
    3. 应用
    public class TemplatePatternDemo {
       public static void main(String[] args) {
     
          Game game = new Cricket();
          game.play();
          System.out.println();
          game = new Football();
          game.play();      
       }
    }
    
    4. 执行程序,输出结果:
    Cricket Game Initialized! Start playing.
    Cricket Game Started. Enjoy the game!
    Cricket Game Finished!
    
    Football Game Initialized! Start playing.
    Football Game Started. Enjoy the game!
    Football Game Finished!
    

    ==3-策略模式-行为型==

    策略
    优点: 
    1、算法可以自由切换。 
    2、避免使用多重条件判断。 
    3、扩展性良好。
    
    缺点: 
    1、策略类会增多。 
    2、所有策略类都需要对外暴露。
    
    使用场景: 
    1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 
    2、一个系统需要动态地在几种算法中选择一种。 
    3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
    
    
    1. 创建接口
    public interface Strategy {
       public int doOperation(int num1, int num2);
    }
    
    2. 创建接口实现类
    public class OperationAdd implements Strategy{
       @Override
       public int doOperation(int num1, int num2) {
          return num1 + num2;
       }
    }
    
    public class OperationSubstract implements Strategy{
       @Override
       public int doOperation(int num1, int num2) {
          return num1 - num2;
       }
    }
    
    public class OperationMultiply implements Strategy{
       @Override
       public int doOperation(int num1, int num2) {
          return num1 * num2;
       }
    }
    
    3. 创建Context类, 整合接口和实现类(拥有接口, 实现动态方法)
    public class Context {
       private Strategy strategy;
     
       public Context(Strategy strategy){
          this.strategy = strategy;
       }
     
       public int executeStrategy(int num1, int num2){
          return strategy.doOperation(num1, num2);
       }
    }
    
    4. 使用 Context 来查看当它改变策略 Strategy 时的行为变化
    public class StrategyPatternDemo {
       public static void main(String[] args) {
          Context context = new Context(new OperationAdd());    
          System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
     
          context = new Context(new OperationSubstract());      
          System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
     
          context = new Context(new OperationMultiply());    
          System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
       }
    }
    
    5. 执行程序,输出结果:
    10 + 5 = 15
    10 - 5 = 5
    10 * 5 = 50
    

    ==4-责任链模式-行为型==

    image
    优点: 
    1、降低耦合度。它将请求的发送者和接收者解耦。 
    2、简化了对象。使得对象不需要知道链的结构。 
    3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 
    4、增加新的请求处理类很方便。
    
    缺点: 
    1、不能保证请求一定被接收。 
    2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 
    3、可能不容易观察运行时的特征,有碍于除错。
    
    使用场景: 
    1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。 
    2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 
    3、可动态指定一组对象处理请求。
    
    1. 创建抽象的记录器类。
    public abstract class AbstractLogger {
       public static int INFO = 1;
       public static int DEBUG = 2;
       public static int ERROR = 3;
     
       protected int level;
     
       //责任链中的下一个元素
       protected AbstractLogger nextLogger;
     
       public void setNextLogger(AbstractLogger nextLogger){
          this.nextLogger = nextLogger;
       }
     
       public void logMessage(int level, String message){
          if(this.level <= level){
             write(message);
          }
          if(nextLogger !=null){
             nextLogger.logMessage(level, message);
          }
       }
     
       abstract protected void write(String message);
       
    }
    
    2. 创建扩展了该记录器类的实体类。
    public class ConsoleLogger extends AbstractLogger {
     
       public ConsoleLogger(int level){
          this.level = level;
       }
     
       @Override
       protected void write(String message) {    
          System.out.println("Standard Console::Logger: " + message);
       }
    }
    
    public class ErrorLogger extends AbstractLogger {
     
       public ErrorLogger(int level){
          this.level = level;
       }
     
       @Override
       protected void write(String message) {    
          System.out.println("Error Console::Logger: " + message);
       }
    }
    
    public class FileLogger extends AbstractLogger {
     
       public FileLogger(int level){
          this.level = level;
       }
     
       @Override
       protected void write(String message) {    
          System.out.println("File::Logger: " + message);
       }
    }
    
    3. 创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。
    public class ChainPatternDemo {
       
       private static AbstractLogger getChainOfLoggers(){
     
          AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
          AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
          AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
     
          errorLogger.setNextLogger(fileLogger);
          fileLogger.setNextLogger(consoleLogger);
     
          return errorLogger;  
       }
     
       public static void main(String[] args) {
          AbstractLogger loggerChain = getChainOfLoggers();
     
          loggerChain.logMessage(AbstractLogger.INFO, 
             "This is an information.");
     
          loggerChain.logMessage(AbstractLogger.DEBUG, 
             "This is an debug level information.");
     
          loggerChain.logMessage(AbstractLogger.ERROR, 
             "This is an error information.");
       }
    }
    
    4. 执行程序,输出结果:
    Standard Console::Logger: This is an information.
    File::Logger: This is an debug level information.
    Standard Console::Logger: This is an debug level information.
    Error Console::Logger: This is an error information.
    File::Logger: This is an error information.
    Standard Console::Logger: This is an error information.
    

    ==5-状态模式-行为型==

    image
    优点: 
    1、封装了转换规则。 
    2、枚举可能的状态,在枚举状态之前需要确定状态种类。 
    3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 
    4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。 
    5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
    
    缺点: 
    1、状态模式的使用必然会增加系统类和对象的个数。 
    2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。 
    3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
    
    使用场景: 
    1、行为随状态改变而改变的场景。 
    2、条件、分支语句的代替者。
    
    1. 创建一个接口。
    public interface State {
       public void doAction(Context context);
    }
    
    2. 创建实现接口的实体类。
    public class StartState implements State {
     
       public void doAction(Context context) {
          System.out.println("Player is in start state");
          context.setState(this); 
       }
     
       public String toString(){
          return "Start State";
       }
    }
    
    public class StopState implements State {
     
       public void doAction(Context context) {
          System.out.println("Player is in stop state");
          context.setState(this); 
       }
     
       public String toString(){
          return "Stop State";
       }
    }
    
    3. 创建 Context 类。
    public class Context {
       private State state;
     
       public Context(){
          state = null;
       }
     
       public void setState(State state){
          this.state = state;     
       }
     
       public State getState(){
          return state;
       }
    }
    
    4. 使用 Context 来查看当状态 State 改变时的行为变化。
    public class StatePatternDemo {
       public static void main(String[] args) {
          Context context = new Context();
     
          StartState startState = new StartState();
          startState.doAction(context);
     
          System.out.println(context.getState().toString());
     
          StopState stopState = new StopState();
          stopState.doAction(context);
     
          System.out.println(context.getState().toString());
       }
    }
    
    5. 执行程序,输出结果:
    Player is in start state
    Start State
    Player is in stop state
    Stop State
    

    ==6-命令模式-行为型==

    image
    优点: 
    1、降低了系统耦合度。 
    2、新的命令可以很容易添加到系统中去。
    
    缺点:
    使用命令模式可能会导致某些系统有过多的具体命令类。
    
    使用场景:
    1、GUI 中每一个按钮都是一条命令。 
    2、模拟 CMD。
    
    1. 创建订单接口
    public interface Order {
       void execute();
    }
    
    2. 创建请求类-股票
    public class Stock {
       
       private String name = "ABC";
       private int quantity = 10;
     
       public void buy(){
          System.out.println("Stock [ Name: "+name+", 
             Quantity: " + quantity +" ] bought");
       }
       public void sell(){
          System.out.println("Stock [ Name: "+name+", 
             Quantity: " + quantity +" ] sold");
       }
    }
    
    3. 创建订单实现类
    public class BuyStock implements Order {
       private Stock abcStock;
     
       public BuyStock(Stock abcStock){
          this.abcStock = abcStock;
       }
     
       public void execute() {
          abcStock.buy();
       }
    }
    
    public class SellStock implements Order {
       private Stock abcStock;
     
       public SellStock(Stock abcStock){
          this.abcStock = abcStock;
       }
     
       public void execute() {
          abcStock.sell();
       }
    }
    
    4. 创建命令调用类-经纪人
    public class Broker {
       private List<Order> orderList = new ArrayList<Order>(); 
     
       public void takeOrder(Order order){
          orderList.add(order);      
       }
     
       public void placeOrders(){
          for (Order order : orderList) {
             order.execute();
          }
          orderList.clear();
       }
    }
    
    5. 应用
    public class CommandPatternDemo {
       public static void main(String[] args) {
          Stock abcStock = new Stock();
     
          BuyStock buyStockOrder = new BuyStock(abcStock);
          SellStock sellStockOrder = new SellStock(abcStock);
     
          Broker broker = new Broker();
          broker.takeOrder(buyStockOrder);
          broker.takeOrder(sellStockOrder);
     
          broker.placeOrders();
       }
    }
    
    6. 执行程序,输出结果:
    Stock [ Name: ABC, Quantity: 10 ] bought
    Stock [ Name: ABC, Quantity: 10 ] sold
    

    ==2-结构型==

    ==7-适配器模式-结构型==

    image
    优点: 
    1、可以让任何两个没有关联的类一起运行。 
    2、提高了类的复用。 
    3、增加了类的透明度。 
    4、灵活性好
    
    缺点: 
    1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。 
    2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
    
    使用场景:
    有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。
    
    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. 创建实现了 AdvancedMediaPlayer 接口的实体类。
    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. 创建实现了 MediaPlayer 接口的适配器类。
    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. 创建实现了 MediaPlayer 接口的实体类。
    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");
          }
       }   
    }
    
    5. 使用 AudioPlayer 来播放不同类型的音频格式。
    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");
          audioPlayer.play("avi", "mind me.avi");
       }
    }
    
    6. 执行程序,输出结果:
    Playing mp3 file. Name: beyond the horizon.mp3
    Playing mp4 file. Name: alone.mp4
    Playing vlc file. Name: far far away.vlc
    Invalid media. avi format not supported
    

    ==8-代理模式-结构型==

    image
    优点: 
    1、职责清晰。 
    2、高扩展性。 
    3、智能化。
    
    缺点:
    1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 
    2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
    
    使用场景:
    1、远程代理。 
    2、虚拟代理。 
    3、Copy-on-Write 代理。 
    4、保护(Protect or Access)代理。 
    5、Cache代理。 
    6、防火墙(Firewall)代理。 
    7、同步化(Synchronization)代理。 
    8、智能引用(Smart Reference)代理。
    
    1. 创建一个接口。
    public interface Image {
       void display();
    }
    
    2. 创建实现接口的实体类。
    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);
       }
    }
    
    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();
       }
    }
    
    3. 当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。
    public class ProxyPatternDemo {
       
       public static void main(String[] args) {
          Image image = new ProxyImage("test_10mb.jpg");
     
          // 图像将从磁盘加载
          image.display(); 
          System.out.println("");
          // 图像不需要从磁盘加载
          image.display();  
       }
    }
    
    4. 执行程序,输出结果:
    Loading test_10mb.jpg
    Displaying test_10mb.jpg
    
    Displaying test_10mb.jpg
    

    ==9-装饰器模式-结构型==

    image
    优点:
    装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
    
    缺点:
    多层装饰比较复杂。
    
    使用场景: 
    1、扩展一个类的功能。 
    2、动态增加功能,动态撤销。
    
    1. 创建 Shape 接口
    public interface Shape {
       void draw();
    }
    
    2. 实现接口
    public class Rectangle implements Shape {
       @Override
       public void draw() {
          System.out.println("Shape: Rectangle");
       }
    }
    
    public class Circle implements Shape {
       @Override
       public void draw() {
          System.out.println("Shape: Circle");
       }
    }
    
    3. 创建实现了 Shape 接口的 抽象装饰类
    public abstract class ShapeDecorator implements Shape {
       protected Shape decoratedShape;
       public ShapeDecorator(Shape decoratedShape){
          this.decoratedShape = decoratedShape;
       }
       public void draw(){
          decoratedShape.draw();
       }  
    }
    
    4. 创建扩展了 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");
       }
    }
    
    5. 使用 RedShapeDecorator 来装饰 Shape 对象
    public class DecoratorPatternDemo {
       public static void main(String[] args) {
          Shape circle = new Circle();
          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();
       }
    }
    
    6. 执行程序,输出结果:
    Circle with normal border
    Shape: Circle
    
    Circle of red border
    Shape: Circle
    Border Color: Red
    
    Rectangle of red border
    Shape: Rectangle
    Border Color: Red
    

    ==10-组合模式-结构型==

    image
    优点: 
    1、高层模块调用简单。 
    2、节点自由增加。
    
    缺点:
    在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
    
    使用场景:
    部分、整体场景,如树形菜单,文件、文件夹的管理。
    
    1. 创建 Employee 类,该类带有 Employee 对象的列表。
    public class Employee {
       private String name;
       private String dept;
       private int salary;
       private List<Employee> subordinates;
     
       //构造函数
       public Employee(String name,String dept, int sal) {
          this.name = name;
          this.dept = dept;
          this.salary = sal;
          subordinates = new ArrayList<Employee>();
       }
     
       public void add(Employee e) {
          subordinates.add(e);
       }
     
       public void remove(Employee e) {
          subordinates.remove(e);
       }
     
       public List<Employee> getSubordinates(){
         return subordinates;
       }
     
       public String toString(){
          return ("Employee :[ Name : "+ name 
          +", dept : "+ dept + ", salary :"
          + salary+" ]");
       }   
    }
    
    2. 使用 Employee 类来创建和打印员工的层次结构。
    public class CompositePatternDemo {
       public static void main(String[] args) {
          Employee CEO = new Employee("John","CEO", 30000);
     
          Employee headSales = new Employee("Robert","Head Sales", 20000);
     
          Employee headMarketing = new Employee("Michel","Head Marketing", 20000);
     
          Employee clerk1 = new Employee("Laura","Marketing", 10000);
          Employee clerk2 = new Employee("Bob","Marketing", 10000);
     
          Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
          Employee salesExecutive2 = new Employee("Rob","Sales", 10000);
     
          CEO.add(headSales);
          CEO.add(headMarketing);
     
          headSales.add(salesExecutive1);
          headSales.add(salesExecutive2);
     
          headMarketing.add(clerk1);
          headMarketing.add(clerk2);
     
          //打印该组织的所有员工
          System.out.println(CEO); 
          for (Employee headEmployee : CEO.getSubordinates()) {
             System.out.println(headEmployee);
             for (Employee employee : headEmployee.getSubordinates()) {
                System.out.println(employee);
             }
          }        
       }
    }
    
    3. 执行程序,输出结果为:
    Employee :[ Name : John, dept : CEO, salary :30000 ]
    Employee :[ Name : Robert, dept : Head Sales, salary :20000 ]
    Employee :[ Name : Richard, dept : Sales, salary :10000 ]
    Employee :[ Name : Rob, dept : Sales, salary :10000 ]
    Employee :[ Name : Michel, dept : Head Marketing, salary :20000 ]
    Employee :[ Name : Laura, dept : Marketing, salary :10000 ]
    Employee :[ Name : Bob, dept : Marketing, salary :10000 ]
    

    ==11-外观模式-结构型==

    image
    优点: 
    1、减少系统相互依赖。 
    2、提高灵活性。 
    3、提高了安全性。
    
    缺点:
    不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。
    
    使用场景: 
    1、为复杂的模块或子系统提供外界访问的模块。 
    2、子系统相对独立。 
    3、预防低水平人员带来的风险。
    
    1. 创建一个接口。
    public interface Shape {
       void draw();
    }
    
    2. 创建实现接口的实体类。
    public class Rectangle implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Rectangle::draw()");
       }
    }
    
    public class Square implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Square::draw()");
       }
    }
    
    public class Circle implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Circle::draw()");
       }
    }
    
    3. 创建一个外观类。
    public class ShapeMaker {
       private Shape circle;
       private Shape rectangle;
       private Shape square;
     
       public ShapeMaker() {
          circle = new Circle();
          rectangle = new Rectangle();
          square = new Square();
       }
     
       public void drawCircle(){
          circle.draw();
       }
       public void drawRectangle(){
          rectangle.draw();
       }
       public void drawSquare(){
          square.draw();
       }
    }
    
    4. 使用该外观类画出各种类型的形状。
    public class FacadePatternDemo {
       public static void main(String[] args) {
          ShapeMaker shapeMaker = new ShapeMaker();
     
          shapeMaker.drawCircle();
          shapeMaker.drawRectangle();
          shapeMaker.drawSquare();      
       }
    }
    
    5. 执行程序,输出结果:
    Circle::draw()
    Rectangle::draw()
    Square::draw()
    

    ==3-创建型==

    ==12-单例模式-创建型==

    优点:
    1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
    2、避免对资源的多重占用(比如写文件操作)。
    
    缺点:
    没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
    
    使用场景:
    1、要求生产唯一序列号。
    2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
    3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
    

    12.1 静态内部类(static inner class)

    是否 Lazy 初始化:是
    是否多线程安全:是
    
    public class Singleton {  
        private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
        }  
        private Singleton (){}  
        public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
        }  
    }
    

    12.2 双检锁/双重校验锁(DCL, double-checked locking)

    是否 Lazy 初始化:是
    是否多线程安全:是
    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;  
        }  
    }
    

    ==13-工厂模式-创建型==

    13.1 简单工厂

    image
    优点: 
    1、一个调用者想创建一个对象,只要知道其名称就可以了。 
    2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 
    3、屏蔽产品的具体实现,调用者只关心产品的接口。
    
    缺点:
    每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
    
    使用场景: 
    1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 
    2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 
    3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。
    
    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.");
       }
    }
    
    public class Circle implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Inside Circle::draw() method.");
       }
    }
    
    3. 创建一个工厂,生成基于给定信息的实体类的对象。
    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;
       }
    }
    
    4. 使用该工厂,通过传递类型信息来获取实体类的对象。
    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();
       }
    }
    
    5. 执行程序,输出结果
    Inside Circle::draw() method.
    Inside Rectangle::draw() method.
    Inside Square::draw() method.
    

    13.2 抽象工厂

    image
    优点:
    当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
    
    缺点:
    产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
    
    使用场景: 
    1、QQ 换皮肤,一整套一起换。 
    2、生成不同操作系统的程序。
    
    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.");
       }
    }
    
    public class Circle implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Inside Circle::draw() method.");
       }
    }
    
    3. 为颜色创建一个接口。
    public interface Color {
       void fill();
    }
    
    4. 创建实现接口的实体类。
    public class Red implements Color {
     
       @Override
       public void fill() {
          System.out.println("Inside Red::fill() method.");
       }
    }
    
    public class Green implements Color {
     
       @Override
       public void fill() {
          System.out.println("Inside Green::fill() method.");
       }
    }
    
    public class Blue implements Color {
     
       @Override
       public void fill() {
          System.out.println("Inside Blue::fill() method.");
       }
    }
    
    5. 为 Color 和 Shape 对象创建抽象类来获取工厂。
    public abstract class AbstractFactory {
       public abstract Color getColor(String color);
       public abstract Shape getShape(String shape) ;
    }
    
    6. 创建扩展了 AbstractFactory 的工厂类,基于给定的信息生成实体类的对象。
    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;
       }
    }
    
    7. 创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。
    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;
       }
    }
    
    8. 使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象。
    public class AbstractFactoryPatternDemo {
       public static void main(String[] args) {
     
          //获取形状工厂
          AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
     
          //获取形状为 Circle 的对象
          Shape shape1 = shapeFactory.getShape("CIRCLE");
     
          //调用 Circle 的 draw 方法
          shape1.draw();
     
          //获取形状为 Rectangle 的对象
          Shape shape2 = shapeFactory.getShape("RECTANGLE");
     
          //调用 Rectangle 的 draw 方法
          shape2.draw();
          
          //获取形状为 Square 的对象
          Shape shape3 = shapeFactory.getShape("SQUARE");
     
          //调用 Square 的 draw 方法
          shape3.draw();
     
          //获取颜色工厂
          AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
     
          //获取颜色为 Red 的对象
          Color color1 = colorFactory.getColor("RED");
     
          //调用 Red 的 fill 方法
          color1.fill();
     
          //获取颜色为 Green 的对象
          Color color2 = colorFactory.getColor("Green");
     
          //调用 Green 的 fill 方法
          color2.fill();
     
          //获取颜色为 Blue 的对象
          Color color3 = colorFactory.getColor("BLUE");
     
          //调用 Blue 的 fill 方法
          color3.fill();
       }
    }
    
    9. 执行程序,输出结果:
    Inside Circle::draw() method.
    Inside Rectangle::draw() method.
    Inside Square::draw() method.
    Inside Red::fill() method.
    Inside Green::fill() method.
    Inside Blue::fill() method.
    

    相关文章

      网友评论

          本文标题:【常用设计模式】观察者-模板-策略-责任链-适配器-代理-装饰器

          本文链接:https://www.haomeiwen.com/subject/zidhuqtx.html