11.面向可复用性和可维护性的设计模式

本文介绍了设计模式中的创建型模式,如工厂方法,结构模式如适配器和装饰器模式,以及行为模式如策略模式和模板方法。这些模式旨在提高代码的可复用性和可维护性,通过不同的设计策略,如接口封装、动态策略选择和对象组合,来适应不断变化的需求。
摘要由CSDN通过智能技术生成

面向可复用性和可维护性的设计模式

1 创建型模式Creational patterns

1.1 工厂方法模式Factory Method pattern

  • 适用范围:
    当client不知道/不确定要创建哪个具体类的实例,或者不想在client代码中指明要具体创建的实例时,用工厂方法。

  • 实现方法:
    定义一个用于创建对象的接口,让该接口的子类型来决定实例化哪一个类,从而使一个类的实例化延迟到其子类。

  • 工厂方法模式

    • 定义一个用于创建对象的接口,让该接口的子类型来决定实例化哪一个类
      在这里插入图片描述
  • 静态工厂方法

    • 定义单独的工厂类,或定义在ADT中
    • 使用static方法,调用时直接类名.方法名不用new
    • 相比于通过构造器(new)构建对象,可以返回原返回类型的任意子类型
      在这里插入图片描述

2 结构模式Structural patterns

2.2 适配器模式Adapter

  • 适用范围:
    将某个类/接口转换为client期望的其他形式。
  • 实现方法:
    • 增加一个接口,用一个子类实现该接口,
    • 在子类中进行委派调用legacy的类方法实现适配器
    • client面向接口编程,使用定义的子类,隐藏了legacy的类
      在这里插入图片描述

2.3 装饰器模式Decorator

  • 适用范围:
    当有许多子类需要自由组合的时候,Java无法多继承,也不适合顺序继承,因此需要一种机制可以为对象增加不同侧面的特性。

  • 实现方法:

    • Component:
      是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象,定义一个对象接口可以给这些对象动态地添加职责
    • ConcreteComponent:
      具体构件是最核心、最原始、最基本的接口或抽象类的实现,需要装饰的就是它
    • Decorator:
      装饰角色一般是一个抽象类,在它的属性里必然有一个private变量指向Component抽象构件。
    • ConcreteDecoratorA和ConcreteDecoratorB:
      具体装饰角色是两个具体的装饰类,要把最核心的、最原始的、最基本的东西装饰成其他东西
      在这里插入图片描述
  • 举例:

    /**
     * 抽象构件,接口
     */
    public interface Componet {
        /**
         * 抽象方法
         */
        public abstract void operate();
    }
    
    
    /**
     * 具体构件
     */
    public class ConcreteComponet extends Componet {
        @Override
        public void operate() {
            //具体的实现
            System.out.println("do something");
        }
    }
    
    /**
     * 装饰类
     */
    public class Decorator extends Componet {
        private Componet componet = null;
    
        /**
         * 通过构造函数传递被修饰者
         *
         * @param componet
         */
        public Decorator(Componet componet) {
            this.componet = componet;
        }
    
        /**
         * 委托给被修者执行
         */
        @Override
        public void operate() {
            this.componet.operate();
        }
    }
    
    
    /**
     * 具体的装饰类
     */
    public class ConcreteDecoratorA extends Decorator {
        /**
         * 通过构造函数传递被修饰者
         *
         * @param componet
         */
        public ConcreteDecoratorA(Componet componet) {
            super(componet);
        }
    
        /**
         * 定义自己的修饰方法
         */
        private void method1() {
            System.out.println("修饰DecoratorA");
        }
    
        @Override
        public void operate() {
            this.method1();
            super.operate();
        }
    }
    
    
    /**
     * 具体的装饰类
     */
    public class ConcreteDecoratorB extends Decorator {
    
        /**
         * 通过构造函数传递被修饰者
         *
         * @param componet
         */
        public ConcreteDecoratorB(Componet componet) {
            super(componet);
        }
    
        /**
         * 定义自己的修饰方法
         */
        private void method2() {
            System.out.println("修饰方法DecoratorB");
        }
    
        @Override
        public void operate() {
            //重写父类的operate方法
            this.method2();
            super.operate();
        }
    }
    
    
    public class Client {
        public static void main(String[] args) {
            Componet componet = new ConcreteComponet();
            //第一次修饰
            componet = new ConcreteDecoratorA(componet);
            //第二次修饰
            componet = new ConcreteDecoratorB(componet);
            //修饰后运行
            componet.operate();
        }
    }
    
  • 示例:
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3 行为模式

3.1 策略模式Strategy

  • 适用范围:
    某个方法在运行时需要client根据需要动态切换算法,而不是写死在代码里,这就需要用到策略模式。

  • 实现方法:
    为不同的实现算法构造抽象接口,利用委托,运行时动态传入client倾向的算法类实例

    • 抽象策略类:通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口
    • 具体策略类:抽象策略类的实现,提供具体的算法
    • 环境类(context):持有一个策略类的引用,最终给客户端调用
//定义接口,抽象策略类:
public interface Strategy {
    void show();
}
//定义一些具体策略:
//策略A
public class StrategyA implements Strategy {
    public void show() {
        System.out.println("策略A");
    }
}
//策略B
public class StrategyB implements Strategy {
    public void show() {
        System.out.println("策略B");
    }
}
//定义环境类,用于连接用户端和服务端,将用户端选择的策略传递给服务端进行挑选、实现
public class Context {                        
    //持有抽象策略角色的引用                              
    private Strategy strategy;                 
    //有参构造方法,将用户输入的策略作为context的私有字段
    public Context(Strategy strategy) {       
        this.strategy = strategy;              
    }
    //通过委派机制展示具体策略
    public void ContextShow(){                
        strategy.show();                       
    }                                          
}  

3.2 模板模式Template Method

  • 适用范围:
    多个客户端共享相同的算法,但在细节上有所不同,即算法由个性部分和共性部分组成。子类中不应重复公共步骤,但需要重用。

  • 实现方法:

    • 抽象类:负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。
      • 模板方法(Template Method):定义了算法的骨架,按某种顺序调用其包含的基本方法。
      • 基本方法:是实现算法各个步骤的方法,是模板方法的组成部分,一般为抽象方法,需要实现类。
    • 具体子类:实现抽象类中所定义的方法。
  • 举例:

        //定义抽象类
    public abstract class CarBuilder {
        protected abstract void BuildSkeleton();
        protected abstract void InstallEngine();
        protected abstract void InstallDoor();
        //模版方法:
        public void BuildCar() {  
            BuildSkeleton();
            InstallEngine();
            InstallDoor();
        }
    }
    //具体实现:
    //保时捷
    public class PorcheBuilder extends CarBuilder {
        protected void BuildSkeleton() {
            System.out.println("Building Porche Skeleton");
        }
        protected void InstallEngine() {
            System.out.println("Installing Porche Engine");
        }
        protected void InstallDoor() {
            System.out.println("Installing Porche Door");
        }
    }
    //甲壳虫
    public class BeetleBuilder extends CarBuilder {
        protected void BuildSkeleton() {
            System.out.println("Building Beetle Skeleton");
        }
        protected void InstallEngine() {
            System.out.println("Installing Beetle Engine");
        }
        protected void InstallDoor() {
            System.out.println("Installing Beetle Door");
        }
    }
    //客户端代码
    public static void main(String[] args) {
        CarBuilder c = new PorcheBuilder();
        c.BuildCar();//直接调用父类方法
        c = new BeetleBuilder();
        c.BuildCar();
    }
    

3.3 迭代器模式Iterator

  • 适用范围:
    客户端希望对放入容器/集合类的一组ADT对象进行遍历访问,而无需关心容器的具体类型,也就是说,不管对象被放进哪里,都应该提供同样的遍历方式

  • 实现方法:迭代器模式包含以下主要角色:

    • 抽象聚合(Abstract Aggregate)角色:定义存储、添加、删除聚合元素以及创建迭代器对象的接口。
    • 具体聚合(Concrete Aggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
    • 抽象迭代器(Abstract Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、next() 等方法。
    • 具体迭代器(Concrete Iterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置
  • 举例:

    //定义迭代器接口,声明hasNext方法和next方法
    public interface StudentIterator {
        boolean hasNext();
        Student next();
    }
    //定义具体的迭代器类,重写所有的抽象方法
    public class StudentIteratorImpl implements StudentIterator {
        private List<Student> list;
        private int position = 0;
        public StudentIteratorImpl(List<Student> list) {
            this.list = list;
        }
        @Override
        public boolean hasNext() {
            return position < list.size();
        }
        @Override
        public Student next() {
            Student currentStudent = list.get(position);
            position ++;
            return currentStudent;
        }
    }
    //定义抽象容器类,包含添加元素,删除元素,获取迭代
    public interface StudentAggregate {
        void addStudent(Student student);
        void removeStudent(Student student);
        StudentIterator getStudentIterator();
    }
    //定义具体的容器类,重写所有方法
    public class StudentAggregateImpl implements StudentAggregate {
        // 创建一个学生列表
        private List<Student> list = new ArrayList<Student>();  
        @Override
        public void addStudent(Student student) {
            this.list.add(student);
        }
        @Override
        public void removeStudent(Student student) {
            this.list.remove(student);
        }
        @Override
        public StudentIterator getStudentIterator() {
            return new StudentIteratorImpl(list);//返回一个迭代器的实例
        }
    }
    
    

3.4 访问者模式Visitor

  • 适用范围:
    对特定类型的object的特定操作(visit),在运行时将
    二者动态绑定到一起,该操作可以灵活更改,无需更改被visit的类

  • 实现方法:

    • 为ADT预留一个将来可扩展功能的“接入点”,外部实现的功能代码可以在不改变ADT本身的情况下通过delegation接入ADT
  • 举例:

    //创建访问者接口
    public interface Person {
        void feed(Cat cat);
        void feed(Dog dog);
    }
    //创建不同的具体访问者角色(主人和其他人),都需要实现Person接口
    public class Owner implements Person {
        @Override
        public void feed(Cat cat) {
            System.out.println("主人喂食猫");
        }
        @Override
        public void feed(Dog dog) {
            System.out.println("主人喂食狗");
        }
    }
    public class Someone implements Person {
        @Override
        public void feed(Cat cat) {
            System.out.println("其他人喂食猫");
        }
        @Override
        public void feed(Dog dog) {
            System.out.println("其他人喂食狗");
        }
    }
    //定义抽象节点 -- 宠物
    public interface Animal {
        void accept(Person person);
    }
    //定义实现Animal接口的具体节点(元素)
    public class Dog implements Animal {
        @Override
        public void accept(Person person) {
            //将具体的访问功能委托给外部传入的visitor
            person.feed(this);//这里的访问操作就是feed
            System.out.println("好好吃,汪汪汪!!!");
        }
    }
    public class Cat implements Animal {
        @Override
        public void accept(Person person) {
            person.feed(this);
            System.out.println("好好吃,喵喵喵!!!");
        }
    }
    //定义对象结构,此案例中就是主人的家
    public class Home {
        private List<Animal> nodeList = new ArrayList<Animal>();
        public void action(Person person) {
            for (Animal node : nodeList) {//需要能够遍历被访问者
                node.accept(person);//被访问者被(谁)访问
            }
        }
        //添加操作
        public void add(Animal animal) {
            nodeList.add(animal);
        }
    }
    //测试
    public class Client {
        public static void main(String[] args) {
            Home home = new Home();
            home.add(new Dog());
            home.add(new Cat());
            Owner owner = new Owner();
            home.action(owner);
            Someone someone = new Someone();
            home.action(someone);
        }
    }
    
    
  • Strategy vs visitor:

    • 二者都是通过delegation建立两个对象的动态联系
      • 但是Visitor强调是的外部定义某种对ADT的操作,该操作于ADT自身关系不大(只是访问ADT),故ADT内部只需要开放accept(visitor)即可,client通过它设定visitor操作并在外部调用。
      • 而Strategy则强调是对ADT内部某些要实现的功能的相应算法的灵活替换。这些算法是ADT功能的重要组成部分,只不过是delegate到外部strategy类而已。
    • 区别:
      • visitor是站在外部client的角度,灵活增加对ADT的各种不同操作(哪怕ADT没实现该操作)
      • strategy则是站在内部ADT的角度,灵活变化对其内部功能的不同配置。

4 设计模式的共性与差异

4.1 设计模式的对比:共性样式1

在这里插入图片描述

  • Adaptor
    在这里插入图片描述

  • Template
    在这里插入图片描述

4.2 设计模式的对比:共性样式2

在这里插入图片描述

  • Strategy
    在这里插入图片描述

  • Iterator
    在这里插入图片描述

  • Factory Method
    在这里插入图片描述

  • Visitor
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SolemnJudgment

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

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

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

打赏作者

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

抵扣说明:

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

余额充值