详细整理全23种设计模式-结构型模式篇2(装饰、外观、组合、享元)

这一篇主要讲结构型模式的后面四种
在这里插入图片描述

结构型模式旨在通过改变代码结构来达到解耦的目的,使得我们的代码容易维护和扩展。

装饰模式

component是逻辑实现类,decorator作为装饰器,用来增强component方法,像是添加小功能等
在这里插入图片描述
例子代码是奶茶和加调料

先声明奶茶接口,拥有描述和价格等属性

	public abstract class Beverage {
        // 返回描述
        public abstract String getDescription();
        // 返回价格
        public abstract double cost();
	}

实现红茶和绿茶

	public class BlackTea extends Beverage {
        public String getDescription() {
            return "红茶";
        }
        public double cost() {
            return 10;
        }
	}
	public class GreenTea extends Beverage {
        public String getDescription() {
            return "绿茶";
        }
        public double cost() {
            return 11;
        }
	}

定义调料接口,这里调料其实就是装饰器decorator

	// 调料
	public abstract class Condiment extends Beverage {}

定义两种调料,这里的关键是注入饮料类,方法内简单的累加

	public class Lemon extends Condiment {
        private Beverage beverage;
        // 这里很关键,需要传入具体的饮料,如需要传入没有被装饰的红茶或绿茶
        public Lemon(Beverage beverage) {
            this.beverage = beverage;
        }
        public String getDescription() {
            // 装饰
            return beverage.getDescription() + ", 加柠檬";
        }
        public double cost() {
            // 装饰
            return beverage.cost() + 2; // 加柠檬需要 2 元
        }
	}

	public class Mango extends Condiment {
        private Beverage beverage;
        public Mango(Beverage beverage) {
            this.beverage = beverage;
        }
        public String getDescription() {
            return beverage.getDescription() + ", 加芒果";
        }
        public double cost() {
            return beverage.cost() + 3;
        }
	}

使用,选择绿茶,芒果和柠檬作为装饰

	public static void main(String[] args) {
        // 首先,我们需要一个基础饮料,红茶、绿茶或咖啡
        Beverage beverage = new GreenTea();
        // 开始装饰
        beverage = new Lemon(beverage); // 先加一份柠檬
        beverage = new Mango(beverage); // 再加一份芒果

        // 如果我们需要 芒果-双份柠檬-红茶
        // Beverage beverage = new Mango(new Lemon(new Lemon(new BlackTea())));

        System.out.println(beverage.getDescription() + " 价格:¥" + beverage.cost());
        //"绿茶, 加柠檬, 加芒果 价格:¥16"
    }

可以加很多装饰
在这里插入图片描述
整体结构如图
在这里插入图片描述
优缺点:

  • 优点是使用灵活,装饰类的排列组合可以实现不同效果
  • 缺点是需要很多注入很多装饰子类去修饰或增强逻辑

使用场景:java IO就是用到了装饰模式
在这里插入图片描述

DataInputStream is = new DataInputStream(
                     new BufferedInputStream(
                     new FileInputStream("")));

个人理解和桥接模式有点像,桥接模式的定义是将抽象化与实现化分离(用组合的方式而不是继承的方式)使得两者可以独立变化。可以减少派生类的增长。这里总结下区别:

  1. 桥接模式中所说的分离,其实是指将结构与实现分离(当结构和实现有可能发生变化时)或属性与基于属性的行为进行分离;而装饰者只是对基于属性的行为进行封闭成独立的类。
  2. 桥接中的行为是横向的行为,行为彼此之间无关联;而装饰者模式中的行为具有可叠加性,其表现出来的结果是一个整体,一个各个行为组合后的一个结果。

外观模式(门面模式)

在日常编码工作中,我们都在有意无意的大量使用外观模式。其实很好理解,直接上代码

先定义图形接口,三种图形的实现:

 public interface Shape {
        void draw();
    }
    public class Circle implements Shape {
        @Override
        public void draw() {
            System.out.println("Circle::draw()");
        }
    }
    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 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();
        }
    }

想要哪个类的方法直接取就行了

public static void main(String[] args) {
	  ShapeMaker shapeMaker = new ShapeMaker();
	
	  shapeMaker.drawCircle();
	  shapeMaker.drawRectangle();
	  shapeMaker.drawSquare();
}

现阶段各种第三方SDK、开源类库,很大概率都会使用外观模式。slf4j就用到了外观去实现logback/log4j等不同的日志框架

组合模式

类中通过 add(node)、remove(node)等方法修改节点,员工/部门架构图很适合用组合模式

	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+" ]");
        }
	}

树结构就是用到了组合模式
在这里插入图片描述
这里把Composite作为树枝,Leaf作为叶,不管是树枝还是叶本质上都是Component

public class CompositePattern {
    public static void main(String[] args) {
        Component c0 = new Composite();
        Component c1 = new Composite();
        Component leaf1 = new Leaf("1");
        Component leaf2 = new Leaf("2");
        Component leaf3 = new Leaf("3");
        c0.add(leaf1);
        c0.add(c1);
        c1.add(leaf2);
        c1.add(leaf3);
        c0.operation();
    }
}

//抽象构件
interface Component {
    public void add(Component c);

    public void remove(Component c);

    public Component getChild(int i);

    public void operation();
}

//树叶构件
class Leaf implements Component {
    private String name;

    public Leaf(String name) {
        this.name = name;
    }

    public void add(Component c) {
    }

    public void remove(Component c) {
    }

    public Component getChild(int i) {
        return null;
    }

    public void operation() {
        System.out.println("树叶" + name + ":被访问!");
    }
}

//树枝构件
class Composite implements Component {
    private ArrayList<Component> children = new ArrayList<Component>();

    public void add(Component c) {
        children.add(c);
    }

    public void remove(Component c) {
        children.remove(c);
    }

    public Component getChild(int i) {
        return children.get(i);
    }

    public void operation() {
        for (Object obj : children) {
            ((Component) obj).operation();
        }
    }
}

享元模式

享元(Flyweight)模式的定义:运用共享技术来复用已经生成的对象

先定义接口和实现

//接口
interface Flyweight {
    public void operation(UnsharedConcreteFlyweight state);
}
//具体实现
class ConcreteFlyweight implements Flyweight {
    private String key;
    ConcreteFlyweight(String key) {
        this.key = key;
        System.out.println("具体享元" + key + "被创建!");
    }
    public void operation(UnsharedConcreteFlyweight outState) {
        System.out.print("具体享元" + key + "被调用,");
        System.out.println("非享元信息是:" + outState.getInfo());
    }
}

该类统一管理Flyweight

//享元工厂角色
class FlyweightFactory {
    private HashMap<String, Flyweight> flyweights = new HashMap<String, Flyweight>();
    public Flyweight getFlyweight(String key) {
        Flyweight flyweight = (Flyweight) flyweights.get(key);
        if (flyweight != null) {
            System.out.println("具体享元" + key + "已经存在,被成功获取!");
        } else {
            flyweight = new ConcreteFlyweight(key);
            flyweights.put(key, flyweight);
        }
        return flyweight;
    }
}

写一个非享元类

//非享元角色
class UnsharedConcreteFlyweight {
    private String info;
    UnsharedConcreteFlyweight(String info) {
        this.info = info;
    }
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
}

使用

 public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight f01 = factory.getFlyweight("a");
        Flyweight f02 = factory.getFlyweight("a");
        Flyweight f03 = factory.getFlyweight("a");
        Flyweight f11 = factory.getFlyweight("b");
        Flyweight f12 = factory.getFlyweight("b");
        f01.operation(new UnsharedConcreteFlyweight("第1次调用a。"));
        f02.operation(new UnsharedConcreteFlyweight("第2次调用a。"));
        f03.operation(new UnsharedConcreteFlyweight("第3次调用a。"));
        f11.operation(new UnsharedConcreteFlyweight("第1次调用b。"));
        f12.operation(new UnsharedConcreteFlyweight("第2次调用b。"));
    }

优点:相同对象只要保存一份,这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。

使用场景:在特定的场景中缓存已经创建的对象,用于提高性能。

最简单的例子:用一个 HashMap 来存放新生成的对象。每次需要一个对象时,先到 HashMap 中看看有没有,如果没有,再生成新的对象,然后将这个对象放入 HashMap 中。

参考:
创建型模式应用实验
25000 字详解 23 种设计模式(多图 + 代码)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值