设计模式学习笔记(一)

本文介绍了设计模式中的创建型模式(如工厂模式、抽象工厂模式、单例模式、建造者模式和原型模式),结构型模式(如适配器模式、桥接模式等)以及行为型模式(如责任链模式和命令模式),并通过实际编程示例展示了它们在软件开发中的应用和价值。

 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。

一、设计模式分类:

Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 中所提到的,总共有 23 种设计模式。这些模式可以分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)、行为型模式(Behavioral Patterns)

序号模式 & 描述包括
1创建型模式
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
  • 工厂模式(Factory Pattern)
  • 抽象工厂模式(Abstract Factory Pattern)
  • 单例模式(Singleton Pattern)
  • 建造者模式(Builder Pattern)
  • 原型模式(Prototype Pattern)
2结构型模式
这些模式关注对象之间的组合和关系,旨在解决如何构建灵活且可复用的类和对象结构。
  • 适配器模式(Adapter Pattern)
  • 桥接模式(Bridge Pattern)
  • 过滤器模式(Filter、Criteria Pattern)
  • 组合模式(Composite Pattern)
  • 装饰器模式(Decorator Pattern)
  • 外观模式(Facade Pattern)
  • 享元模式(Flyweight Pattern)
  • 代理模式(Proxy Pattern)
3行为型模式
这些模式关注对象之间的通信和交互,旨在解决对象之间的责任分配和算法的封装。
  • 责任链模式(Chain of Responsibility Pattern)
  • 命令模式(Command Pattern)
  • 解释器模式(Interpreter Pattern)
  • 迭代器模式(Iterator Pattern)
  • 中介者模式(Mediator Pattern)
  • 备忘录模式(Memento Pattern)
  • 观察者模式(Observer Pattern)
  • 状态模式(State Pattern)
  • 空对象模式(Null Object Pattern)
  • 策略模式(Strategy Pattern)
  • 模板模式(Template Pattern)
  • 访问者模式(Visitor Pattern)
4J2EE 模式
这些设计模式特别关注表示层。这些模式是由 Sun Java Center 鉴定的。
  • MVC 模式(MVC Pattern)
  • 业务代表模式(Business Delegate Pattern)
  • 组合实体模式(Composite Entity Pattern)
  • 数据访问对象模式(Data Access Object Pattern)
  • 前端控制器模式(Front Controller Pattern)
  • 拦截过滤器模式(Intercepting Filter Pattern)
  • 服务定位器模式(Service Locator Pattern)
  • 传输对象模式(Transfer Object Pattern)

二、设计模式介绍 

 1.创建型模式:

 1).工厂模式:

我们举个手机厂的例子:用户需要手机产品时,直接提供手机产品名称给工厂,由手机工厂完成根据提供的信息决定提供哪个具体产品,即使用哪个具体产品的实现对产品进行实例化。

代码示例:

public class HuaWeiPhoneFactory extends HuaWeiFactory {

    @Override
    public IPhone getPhone(String phoneType) throws Exception {
        switch (phoneType) {
            case "Mate60":
                return new HuaWeiMate60();
            case "Mate60Pro":
                return new HuaWeiMate60Pro();
            case "Mate60RS":
                return new HuaWeiMate60RS();
            default:
                throw new Exception("Phone type does not exist");
        }
    }
}

 HuaWei手机工厂根据传入的产品类型名确定具体生产Mate60、Mate60Pro还是Mate60RS。

用户在创建手机对象时直接使用Phone接口,而不用分别去通过new创建对象,大概就是:


    HuaWeiMate60 getHuaWeiMate60() {
        return new HuaWeiMate60();
    }
    HuaWeiMate60Pro getHuaWeiMate60Pro() {
        return new HuaWeiMate60Pro();
    }
    HuaWeiMate60RS getHuaWeiMate60RS() {
        return new HuaWeiMate60RS();
    }

从上面的新建对象方式变成下面的方式 

    IPhone getPhone(String type) throws Exception {
        HuaWeiPhoneFactory factory = new HuaWeiPhoneFactory();
        return factory.getPhone(type);
    }

工厂模式下,当新产品发布时,用户不需要新增getNewPhone方法,而是由工厂方法对产品扩展进行适配。

2).抽象工厂模式:

现在huawei厂家不仅生产手机,还生产汽车;同时还有一家厂商xiaomi也同时生产手机和汽车。

这时需要新增huawei汽车工厂,xiaomi手机工厂,xiaomi汽车工厂,右回到了工厂模式前的境况,于是将工厂抽象出工厂的工厂用于具体工厂的创建。

代码示例:

public class HuaWeiFactory extends AbstractFactory {

    @Override
    public IPhone getPhone(String phoneType) throws Exception {
        switch (phoneType) {
            case "Mate60":
                return new HuaWeiMate60();
            case "Mate60Pro":
                return new HuaWeiMate60Pro();
            case "Mate60RS":
                return new HuaWeiMate60RS();
            default:
                throw new Exception("Phone type does not exist");
        }
    }

    @Override
    public ICar getCar(String carType) throws Exception {
        switch (carType) {
            case "AitoM7":
                return new HuaWeiAitoM7();
            case "AitoM9":
                return new HuaWeiAitoM9();
            default:
                throw new Exception("Car type does not exist");
        }
    }
}
public class XiaoMiFactory extends AbstractFactory{
    @Override
    IPhone getPhone(String phoneType) throws Exception {
        switch (phoneType) {
            case "XiaoMiMix":
                return new XiaoMiMix();
            case "XiaoMiRedMi":
                return new XiaoMiRedMi();
            default:
                throw new Exception("Phone type does not exist");
        }
    }

    @Override
    ICar getCar(String carType) throws Exception {
        switch (carType) {
            case "Su7":
                return new XiaoMiSu7();
            case "Su8":
                return new XiaoMiSu8();
            case "Su9":
                return new XiaoMiSu9();
            default:
                throw new Exception("Car type does not exist");
        }
    }
}

 通过abstractFactory获取具体工厂,类似前面工厂模式下通过IPhone接口获取具体手机产品


    public AbstractFactory getFactory(String factoryType) throws Exception {
        switch (factoryType) {
            case "HuaWei":
                return new HuaWeiFactory();
            case "XiaoMi":
                return new XiaoMiFactory();
            default:
                throw new Exception("factory does not exist");
        }
    }

3).单例模式:

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,并提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

优点:

1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

单例模式的几种实现方式:

饿汉式:

非懒加载,线程安全

类装载时完成实例化,基于 classloader 机制避免了多线程的同步问题,但是在未使用时装载也浪费了内存资源。

public class SingletonInstance {

    private static SingletonInstance instance = new SingletonInstance();

    private SingletonInstance() {
    }

    public static SingletonInstance getInstance() {
        return instance;
    }
}

懒汉式:

懒加载,线程不安全

多线程场景下可能出现多次实例化的情况。


public class SingletonInstance {

    private static SingletonInstance instance;

    private SingletonInstance() {
    }

    public static SingletonInstance getInstance() {
        if (instance == null) {
            instance = new SingletonInstance();
        }
        return instance;
    }
}

 应对线程安全问题,出现了加锁的懒汉式:

懒加载,且线程安全,但是synchronized放在这里会降低效率

public class SingletonInstance {

    private static SingletonInstance instance;

    private SingletonInstance() {
    }

    public static synchronized SingletonInstance getInstance() {
        if (instance == null) {
            instance = new SingletonInstance();
        }
        return instance;
    }
}

双重校验锁:

 懒加载,线程安全

这里仅对实例化操作加锁,实例化后再次访问时直接返回,提高了效率。另instance添加修饰符volatile防止可能的指令重排造成线程安全问题。

public class SingletonInstance {

    private static volatile SingletonInstance instance;

    private SingletonInstance() {
    }

    public static SingletonInstance getInstance() {
        if (instance == null) {
            synchronized (instance) {
                if (instance == null) {
                    instance = new SingletonInstance();
                }
            }
        }
        return instance;
    }
}

4).建造者模式:

主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的组合构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是组成它的各个部分却相对稳定。

比如:我们去肯德基的时候,会有各种套餐,这个套餐相对于套餐中的单品就是一个相对复杂的对象。不同套餐由不同单品组合而成,套餐变化时只需要修改单品的拼装,而不用去逐个去修改单品。

又比如:我们想要买一台电脑时,考虑到个人使用偏好,个人预算等,就会出现不同的配置组合。

有的要求计算性能,有的要求图像处理能力,有的要求便携轻便,有的则更注重酷炫的外形等。

我们以构建computer为例:

computer由一系列组件(component)组成:

public class Computer {
    List<Component> components = new ArrayList<>();
    public void addItem(Component component) {
        components.add(component);
    }
}

 组件接口,各具体组件需实现此接口:

public interface Component {
    /**
     * 名称
     * @return String
     */
    String name();

    /**
     * 品牌
     * @return String
     */
    String brand();

    /**
     * 性能
     * @return String
     */
    String performance();

    /**
     * 价格
     * @return float
     */
    float price();
}

ComputerBuilder建造者,使用各具体组件拼装具体产品:


public class ComputerBuilder {
    /**
     * 游戏PC
     * @return computer
     */
    Computer buildGamePC() {
        Computer computer = new Computer();
        computer.addItem(new IntelG13I3());
        computer.addItem(new SamSungSSD());
        computer.addItem(new SamSungMem());
        computer.addItem(new AocMonitor());
        return computer;
    }

    /**
     * 工作PC
     * @return computer
     */
    Computer buildWorkPC() {
        Computer computer = new Computer();
        computer.addItem(new AMDRyzen5_5600GT());
        computer.addItem(new KingstonSSD());
        computer.addItem(new SamSungMem());
        computer.addItem(new AocMonitor());
        return computer;
    }
}

 具体组件实现重新对应抽象类:

public class IntelG13I3 extends Cpu {
    @Override
    public String name() {
        return "Intel i3-13100";
    }

    @Override
    public String brand() {
        return "Intel";
    }

    @Override
    public String performance() {
        return "4.50 GHz/3.40 GHz/ 12 MB Intel® Smart Cache";
    }

    @Override
    public float price() {
        return 1000;
    }
}

public class SamSungSSD extends Disk {
    @Override
    public String name() {
        return "SanSang SSD 256G";
    }

    @Override
    public String brand() {
        return "SanSang";
    }

    @Override
    public String performance() {
        return "3500MB/s";
    }

    @Override
    public float price() {
        return 300;
    }
}

整体类关系:

5).原型模式:

原型模式(Prototype Pattern)用于重复创建复杂对象(一般该复杂对象的初始化过程比较消耗资源),通过拷贝现有对象的方式避免重复执行初始化过程,提高创建效率。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一。用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。

原型模式拷贝现有对象的方式分为浅拷贝和深拷贝两种,浅拷贝通过实现cloneable接口,重写Object的clone()方法实现;深拷贝通过实现Serializable接口,读写二进制流方式实现。

                                                                                                                          图片转自runoob.com

 抽象原型类shape:

public abstract class Shape implements Cloneable {
   
   private String id;
   protected String type;
   
   abstract void draw();
   
   public String getType(){
      return type;
   }
   
   public String getId() {
      return id;
   }
   
   public void setId(String id) {
      this.id = id;
   }
   
   public Object clone() {
      Object clone = null;
      try {
         clone = super.clone();
      } catch (CloneNotSupportedException e) {
         e.printStackTrace();
      }
      return clone;
   }
}

具体实体类:

public class Rectangle extends Shape {
 
   public Rectangle(){
     type = "Rectangle";
   }
 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

public class Square extends Shape {
 
   public Square(){
     type = "Square";
   }
 
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}

public class Circle extends Shape {
 
   public Circle(){
     type = "Circle";
   }
 
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

shape缓存类:

public class ShapeCache {
    
   private static Hashtable<String, Shape> shapeMap 
      = new Hashtable<String, Shape>();
 
   public static Shape getShape(String shapeId) {
      Shape cachedShape = shapeMap.get(shapeId);
      return (Shape) cachedShape.clone();
   }
 
   // 对每种形状都运行数据库查询,并创建该形状
   // shapeMap.put(shapeKey, shape);
   // 例如,我们要添加三种形状
   public static void loadCache() {
      Circle circle = new Circle();
      circle.setId("1");
      shapeMap.put(circle.getId(),circle);
 
      Square square = new Square();
      square.setId("2");
      shapeMap.put(square.getId(),square);
 
      Rectangle rectangle = new Rectangle();
      rectangle.setId("3");
      shapeMap.put(rectangle.getId(),rectangle);
   }
}

 实体类的具体使用者:

public class PrototypePatternDemo {
   public static void main(String[] args) {
      ShapeCache.loadCache();
 
      Shape clonedShape = (Shape) ShapeCache.getShape("1");
      System.out.println("Shape : " + clonedShape.getType());        
 
      Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
      System.out.println("Shape : " + clonedShape2.getType());        
 
      Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
      System.out.println("Shape : " + clonedShape3.getType());        
   }
}

2. 结构型模式

6).适配器模式:

适配器模式(Adapter Pattern)充当两个不兼容接口之间的桥梁,属于结构型设计模式。如我们常用的充电器,又叫做电源适配器,它的作用是将插座(服务提供者,也就是待适配对象)输出的220V电压转换成设备(消费者,也就是最后需要输出的接口)所需的5V、12V、或其他电压输出。

6.1) 类适配器

类适配器继承服务提供者(插座),并实现消费者所需的接口(设备所需接口)。

public class ServiceProvider {
    // 提供220V电压
    public String getVoltage() {
        return "220V";
    }
    // 提供默认插孔
    public String getPlugholesOnJack() {
        return "default";
    }
}

// 类适配器继承服务提供者并实现消费者所需接口
public class ClassAdapter extends ServiceProvider implements IVoltageAdapter {
    @Override
    public String outputVoltage() {
        String originVoltage = getVoltage();
        // do something to adapt the origin voltage to the voltage device needed
        // for example here changed the voltage to 5V.
        return "5V";
    }
}

public class DeviceA {
    ClassAdapter classAdapter = new ClassAdapter();
    // 充电
    public String charge() {
        String voltage = classAdapter.outputVoltage();
        if ("5V".equals(voltage)) {
//            System.out.println("charging with 5V");
            return "charging with 5V";
        } else {
//            System.out.println("failed to charge with " + voltage);
            return "failed to charge with " + voltage;
        }
    }
}

6.2) 对象适配器

对象适配器与类适配器不同的是,它不在继承服务提供者,而是持有服务提供者的实例,并实现消费者所需的接口(设备所需接口)。对象适配器不在继承服务提供者,实现了与服务提供者的解耦。

public class ServiceProvider {
    // 提供220V电压
    public String getVoltage() {
        return "220V";
    }
    // 提供默认插孔
    public String getPlugholesOnJack() {
        return "default";
    }
}

// 对象配器持有服务提供者对象实例并实现消费者所需接口
public class ObjectAdapter implements IVoltageAdapter {
    ServiceProvider provider = new ServiceProvider();
    @Override
    public String outputVoltage() {
        String originVoltage = provider.getVoltage();
        // do something to adapt the origin voltage to the voltage device needed
        // for example here changed the voltage to 5V.
        return "5V";
    }
}

public class DeviceA {
    ObjectAdapter objectAdapter = new ObjectAdapter();
    // 充电
    public String charge() {
        String voltage = objectAdapter.outputVoltage();
        if ("5V".equals(voltage)) {
//            System.out.println("charging with 5V");
            return "charging with 5V";
        } else {
//            System.out.println("failed to charge with " + voltage);
            return "failed to charge with " + voltage;
        }
    }
}

6.3) 缺省适配器

上述电源适配器的场景,考虑若存在多个设备:设备A需要5V电压,两孔插口、设备B需要12V电压,三孔插口、设备C需要5V电压,两孔插口、设备D需要12V电压,三孔插口。

设备所需电压所需插口
A5V
B5V
C12V
D12V

这时每个设备需要在它的适配器中实现电压处理方法来获取需要的电压,及插口处理方法,来获取;若有更多类型的设备,所需实现的接口方法可能会更多。

缺省适配器使用了一个AbstractAdapter对每个接口方法做了空实现,后续设备仅需继承AbstractAdapter,并实现自己需要的接口方法即可,而不需要关心其余接口方法。

JDK中的抽象类MouseAdapter就是一个缺省适配器,它分别实现了MouseListener, MouseWheelListener, MouseMotionListener接口的每一个方法(空实现)。

对于点击事件,当你的空间只需要处理点击,拖拽事件时,可以只重新者两个方法,而不用关心其余的鼠标移动、鼠标按压,鼠标释放,滚轮移动等方法。

7).桥接模式:

桥接模式用于把抽象化与实现化解耦,使得二者可以独立变化,属于结构型模式的一种。

以画图为例,下图中画图关注两个维度,形状和颜色。IDrawApi决定了图形类型的扩展,AbstractPen决定了不同颜色画笔的扩展。

桥接模式的几个角色:

  • 抽象类(Abstraction):上图中的AbstractPen,定义了抽象部分的接口方法draw(),同时维护了一个指向实现部分的引用drawApi。
  • 扩展抽象类(Refined Abstraction):上图中的RedPen和BlackPen。
  • 实现层接口(Implementor):上图中的IDrawApi定义了实现部分的接口方法drawImpl()。
  • 具体实现类(Concrete Implementor):上图中的Circle和Triangle,完成实现层接口的具体实现。

代码实现,抽象类:

public abstract class AbstractPen {
    IDrawApi drawApi;

    public AbstractPen(IDrawApi drawApi) {
        this.drawApi = drawApi;
    }

    public abstract void draw();
}

扩展抽象类:

public class BlackPen extends AbstractPen {
    public BlackPen(IDrawApi drawApi) {
        super(drawApi);
    }

    @Override
    public void draw() {
        System.out.println("draw picture with black pen");
        drawApi.drawImpl();
    }
}

public class RedPen extends AbstractPen {
    public RedPen(IDrawApi drawApi) {
        super(drawApi);
    }

    @Override
    public void draw() {
        System.out.println("draw picture with red pen");
        drawApi.drawImpl();
    }
}

 实现层接口:

public interface IDrawApi {
    void drawImpl();
}

实现层具体实现类:

public class Circle implements IDrawApi {
    @Override
    public void drawImpl() {
        System.out.println("Drawing Circle");
    }
}

public class Triangle implements IDrawApi {
    @Override
    public void drawImpl() {
        System.out.println("Draw Triangle");
    }
}

8).过滤器模式:

过滤器模式允许开发者使用不同的条件来过滤对象,通过与或非运算将一系列条件连接起来,各个条件的实现之间解耦。主要用于条件筛选,如

  • 图书管理,在图书馆查找图书时,根据书名、作者、图书类型、出版商等条件筛选。
  • 网购平台,根据商品的名称、品牌、价格、种类等对商品进行筛选。

以图书管理为例:

过滤器接口:

import java.util.List;
// 过滤器接口,所有过滤器均实现此接口
public interface IFilter {
    List<Book> doFilter(List<Book> books);
}

业务过滤器 :

// 作者过滤器
public class AuthorFilter implements IFilter {
    private final String author;
    // 过滤条件作者名author
    public AuthorFilter(String author) {
        this.author = author;
    }
    // 过滤作者名称包含author的书籍
    @Override
    public List<Book> doFilter(List<Book> books) {
        return books.stream().filter(o -> o.getAuthor().contains(author)).collect(Collectors.toList());
    }
}

public class NameFilter implements IFilter{
    private final String name;
    // 过滤条件书籍名称name
    public NameFilter(String name) {
        this.name = name;
    }
    // 根据数据名称对书籍进行过滤
    @Override
    public List<Book> doFilter(List<Book> books) {
        return books.stream().filter(o->o.getName().contains(name)).collect(Collectors.toList());
    }
}

public class TypeFilter implements IFilter {
    private final String type;
    // 书籍分类
    public TypeFilter(String type) {
        this.type = type;
    }

    // 根据书籍分类对书籍进行过滤
    @Override
    public List<Book> doFilter(List<Book> books) {
        return books.stream().filter(o -> o.getType().contains(type)).collect(Collectors.toList());
    }
}

通用逻辑过滤器:

public class AndFilter implements IFilter {

    List<IFilter> filters;
    // 有与关系的多个过滤器
    public AndFilter(List<IFilter> filters) {
        this.filters = filters;
    }
    // 遍历过滤器对结果进行过滤求交集
    @Override
    public List<Book> doFilter(List<Book> books) {
        Iterator<IFilter> iterator = filters.iterator();
        List<Book> result = new ArrayList<>(books);
        while(iterator.hasNext()) {
            result = iterator.next().doFilter(result);
        }
        return result;
    }
}

public class OrFilter implements IFilter{

    List<IFilter> filters;
    // 有或关系的多个过滤器
    public OrFilter(List<IFilter> filters) {
        this.filters = filters;
    }

    // 遍历过滤器对结果进行过滤求并集
    @Override
    public List<Book> doFilter(List<Book> books) {
        return filters.stream().map(o
                -> o.doFilter(books)).flatMap(List::stream).distinct().collect(Collectors.toList());
    }
}

 使用:

public class Consumer {
    public static void main(String[] args) {
        List<Book> books = new ArrayList<>(Arrays.asList(
                new Book("天蚕土豆", "小说", "斗破苍穹"),
                new Book("天蚕土豆", "小说", "舞动乾坤"),
                new Book("天蚕土豆", "小说", "大主宰"),
                new Book("杨守敬", "地理", "水经注疏"),
                new Book("郦道元", "地理", "水经注"),
                new Book("郭璞", "地理", "水经")
        ));

        IFilter novelFilter = new TypeFilter("小说");
        IFilter authorFilter = new AuthorFilter("天蚕土豆");
        IFilter andFilter = new AndFilter(Arrays.asList(novelFilter, authorFilter));

        IFilter nameFilter = new NameFilter("水经注疏");
        authorFilter = new AuthorFilter("郭璞");
        IFilter orFilter = new OrFilter(Arrays.asList(nameFilter, authorFilter));


        System.out.println("andFilter.doFilter(books) = \r\n" + 
            andFilter.doFilter(books));

        System.out.println("orFilter.doFilter(books) =  \r\n" + 
            orFilter.doFilter(books));
    }
}

 运行结果如下:


andFilter.doFilter(books) = 
[Book: {name='斗破苍穹', author='天蚕土豆', type='小说'}, Book: {name='舞动乾坤', author='天蚕土豆', type='小说'}, Book: {name='大主宰', author='天蚕土豆', type='小说'}]
orFilter.doFilter(books) =  
[Book: {name='水经注疏', author='杨守敬', type='地理'}, Book: {name='水经', author='郭璞', type='地理'}]

9). 组合模式:

组合模式又叫做部分-整体模式,组合模式下对部分与整体的处理具有一致性。

如java swing下的组件,Panel、Button、Frame等组件均继承自Component,均可以添加子组件,或设置鼠标事件监听等。

代码示例:


import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;

public class Main {
    public static void main(String[] args) {
        // Frame
        JFrame frame = new JFrame();
        frame.show();
        frame.setSize(500, 800);
        // panel
        JPanel panel = new JPanel();
        // checkbox
        JCheckBox checkBox = new JCheckBox();
        // button
        JButton button = new JButton();
        // 都可以添加鼠标监听
        addMouseListener(frame);
        addMouseListener(panel);
        addMouseListener(checkBox);
        addMouseListener(button);
        // 都可以设置布局
        frame.setLayout(new BorderLayout());
        panel.setLayout(new BorderLayout());
        checkBox.setLayout(new FlowLayout());
        button.setLayout(new FlowLayout());
        // 设置名称
        frame.setName("frame");
        panel.setName("panel");
        checkBox.setName("checkBox");
        button.setName("button");
        // 添加子component
        frame.add(panel, BorderLayout.SOUTH);
        panel.add(button, BorderLayout.SOUTH);
        panel.add(checkBox, BorderLayout.EAST);
        checkBox.add(new JButton("OK"));
        button.add(new JLabel("label"));
        //......
        frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    }

    public static void addMouseListener(Component c) {
        c.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("clicked " + getButton(e) + " on " + c.getName());
            }
        });
    }

    public static String getButton(MouseEvent e) {
        switch (e.getButton()) {
            case 1:
                return "left button";
            case 2:
                return "wheel button";
            case 3:
                return "right button";
            default:
                return "";
        }
    }
}

 由于组合模式下部分与整体的处理逻辑的一致性,开发者理解任一部分的使用就能触类旁通的理解其他部分或整体的使用,使得组件的学习成本降低,更容易理解。

10).装饰器模式:

装饰器模式通过将现有对象封装到装饰器类中,实现向一个现有的对象添加新的功能,同时又可以不改变其结构。

如一升水,我们把它放到不同形状的容器中,它就拥有了不同的形态,但其本身的性质没有被改变。

代码示例,现有对象抽象及其实现:

// 水,现有对象接口
public interface Water {
    void getWater();
}

// 纯净水,现有对象具体实现
public class PureWater implements Water{
    @Override
    public void getWater() {
        System.out.println("pure water");
    }
}

// 矿泉水,现有对象具体实现
public class MineralWater implements Water{
    @Override
    public void getWater() {
        System.out.println("mineral water");
    }
}

装饰器抽象及其实现:

// 抽象装饰器
public abstract class WaterDecorator implements Water{
    Water water;
    public WaterDecorator(Water water) {
        this.water = water;
    }
    public void getWater() {
        water.getWater();
    };
}
// 装饰器具体实现,将水装进杯子
public class CupDecorator extends WaterDecorator {
    public CupDecorator(Water water) {
        super(water);
    }

    @Override
    public void getWater() {
        water.getWater();
        setContainer(water);
    }

    private void setContainer(Water water) {
        System.out.println("pour water into a cup");
    }
}
// 装饰器具体实现,将水装进瓶子
public class BottleDecorator extends WaterDecorator{
    public BottleDecorator(Water water) {
        super(water);
    }

    @Override
    public void getWater() {
        water.getWater();
        setContainer(water);
    }

    private void setContainer(Water water) {
        System.out.println("pour water into a bottle");
    }
}

使用示例:

public class Main {
    public static void main(String[] args) {
        Water pure = new PureWater();
        Water mineral = new MineralWater();
        WaterDecorator cupOfPure = new CupDecorator(pure);
        WaterDecorator cupOfMineral = new CupDecorator(mineral);
        WaterDecorator bottleOfPure = new BottleDecorator(pure);
        WaterDecorator bottleOfMineral = new BottleDecorator(mineral);
        cupOfPure.getWater();
        cupOfMineral.getWater();
        bottleOfPure.getWater();
        bottleOfMineral.getWater();
    }
}

输出如下: 

----------------------------------------------------------未完待续-----------------------------------------------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JebWoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值