设计模式详解(3)-- 结构型模式详解上

本系列文章:
设计模式详解(1)-- 初识设计模式
设计模式详解(2)-- 创建型模式详解
设计模式详解(3)-- 结构型模式详解上
设计模式详解(4)-- 结构型模式详解下
设计模式详解(5)-- 行为型模式详解上
设计模式详解(6) – 行为型模式详解下

本博客专门介绍结构型模式中的适配器模式,桥接模式,过滤器模式,组合模式

适配器模式(Adapter Pattern)

适配器就是一种适配中间件,它存在于不匹配的二者之间,用于连接二者,将不匹配变得匹配,简单点理解就是平常所见的转接头,转换器之类的存在。适配器模式可以细分为三种:类适配器、对象适配器、接口适配器。

现在我们有一个需求,我们有一个usb插口,但插座只能接ps2接口,怎么办?是的,弄个转换器,将ps2插头转换成为usb插头就可以使用了。

类适配器模式

它通过继承来实现适配器功能。

示例

分别创建ps2接口与usb接口

public interface Ps2 {

	void ps2Using();
}

public interface Usb {

	void usbUsing();
}

然后我们创建一个usb接口的实现类

//usb接口实现类
public class Usber implements Usb{

	@Override
	public void usbUsing() {
		System.out.println("usb接口连接.....");
	}
}

接着我们实现一个适配器

public class Adapter extends Usber implements Ps2{

	@Override
	public void ps2Using() {
		super.usbUsing();
	}
}

到这一步,我们其实已经可以把ps2接口转化为usb接口了。测试一下

public class Clienter {

	public static void main(String[] args) {
		Ps2 use = new Adapter();
		use.ps2Using();
	}
}

结果一切正常

usb接口连接…

对象适配器模式

在适配器的实现上,与类适配器模式不同,并没有继承usb类,而是使用组合的形式,在其内部维护一个usb对象,从而达到适配的目的。

示例

对适配器的实现的具体代码

public class Adapter implements Ps2{

	Usb usb;
	
	public Adapter(Usb usb) {
		this.usb = usb;
	}
	
	@Override
	public void ps2Using() {
		usb.usbUsing();
	}
}

测试

public class Clienter {

	public static void main(String[] args) {
		Ps2 use = new Adapter(new Usber());
		use.ps2Using();
	}
}

结果与上面相同

接口适配器模式

当存在这样一个接口,其中定义了N多的方法,而我们现在却只想使用其中的一个到几个方法,如果我们直接实现接口,那么我们要对所有的方法进行实现,哪怕我们仅仅是对不需要的方法进行置空(只写一对大括号,不做具体方法实现)也会导致这个类变得臃肿,调用也不方便,这时我们可以使用一个抽象类作为中间件,即适配器,用这个抽象类实现接口,而在抽象类中所有的方法都进行置空,那么我们在创建抽象类的继承类,而且重写我们需要使用的那几个方法即可。

示例

我们有一个目标接口A

public interface A {
    void a();
    void b();
    void c();
    void d();
    void e();
    void f();
}

在适配器Adapter中,我们将所有方法直接置空即可

public abstract class Adapter implements A {
    public void a(){}
    public void b(){}
    public void c(){}
    public void d(){}
    public void e(){}
    public void f(){}
}

有了这个适配器,我们可以根据自己的具体需求构建自己的实现类,只需继承Adapter即可。

public class Ashili extends Adapter {
    public void a(){
        System.out.println("实现A方法被调用");
    }
    public void d(){
        System.out.println("实现d方法被调用");
    }
}

测试一下

public class Clienter {

    public static void main(String[] args) {
        A a = new Ashili();
        a.a();
        a.d();
    }

}

桥接模式(Bridge Pattern)

桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。

使用场景

  • 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
  • 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
  • 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。

下面我们通过实例演示桥接模式,目标是画出不同颜色,不同形状的图形。

我们先创建一个颜色接口,它可以绘制不同的颜色

public interface Color {

	void print(String shape);
}

再写两个实现类

public class Red implements Color {

	@Override
	public void print(String shape) {
		System.out.println("我要绘制" + "红色的" + shape);
	}

}

public class Blue implements Color{

	@Override
	public void print(String shape) {
		System.out.println("我要绘制" + "蓝色的" + shape);
	}

}

接着我们建立一个抽象图形类

public abstract class Shape{
	
	protected Color color;
	
	public void setColor(Color color) {
		this.color = color;
	}
	
	abstract void draw();
}

再写两个图形实现类,一个绘制圆,一个绘制方形

public class Circle extends Shape{

	@Override
	void draw() {
		color.print("圆形");
	}
}

public class Square extends Shape{

	@Override
	void draw() {
		color.print("方形");
	}
}

测试一下

public class Client {

	public static void main(String[] args) {
		Shape circle = new Circle();
		circle.setColor(new Red());
		circle.draw();
		
		Shape square = new Square();
		square.setColor(new Blue());
		square.draw();
	}
}

我要绘制红色的圆形
我要绘制蓝色的方形

成功将形状与颜色桥接到了一起

过滤器模式(Filter、Criteria Pattern)

顾名思义,过滤器模式允许开发人员使用不同的标准来过滤一组对象

来,我们先建立一个对象

public class Person {

	private String name;
	private String gender;
	private int age;
	
	public Person(String name, String gender, int age) {
		super();
		this.name = name;
		this.gender = gender;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", gender=" + gender + ", age=" + age + "]";
	}
}

然后我们再建立一个过滤器接口

//过滤器接口
public interface Criteria {

	//执行过滤操作
	List<Person> criteria(List<Person> list);
}

再写两个过滤类

//对18到28岁的年龄过滤器
public class AgeCriteria implements Criteria{

	@Override
	public List<Person> criteria(List<Person> list) {
		List<Person> newList = new ArrayList<Person>();
		
		for (Person person : list) {
			if(person.getAge()>=18 && person.getAge()<=28) {
				newList.add(person);
			}
		}
		
		return newList;
	}
}

//对男性的过滤器
public class MaleCriteria implements Criteria{

	@Override
	public List<Person> criteria(List<Person> list) {
		List<Person> newList = new ArrayList<Person>();
		for (Person person : list) {
			if(person.getGender().equals("male")) {
				newList.add(person);
			}
		}
		
		return newList;
	}
}

测试一下

public class Test {

	public static void main(String[] args) {
		List<Person> list = new ArrayList<Person>();
		
		list.add(new Person("aaa", "male", 14));
		list.add(new Person("bbb", "male", 70));
		list.add(new Person("ccc", "male", 19));
		list.add(new Person("ddd", "female", 22));
		list.add(new Person("eee", "female", 45));
		list.add(new Person("fff", "female", 25));
		list.add(new Person("ggg", "female", 11));
		
		//执行18到28岁的年龄过滤器
		Criteria ageCriteria = new AgeCriteria();
		List<Person> list1 = ageCriteria.criteria(list);
		
		System.out.println("执行18到28岁的年龄过滤器");
		for (Person person : list1) {
			System.out.println(person);
		}
		
		//执行男性的过滤器
		Criteria maleCriteria = new MaleCriteria();
		List<Person> list2 = maleCriteria.criteria(list);
		
		System.out.println("执行男性的过滤器");
		for (Person person : list2) {
			System.out.println(person);
		}
	}
}

过滤成功

执行18到28岁的年龄过滤器
Person [name=ccc, gender=male, age=19]
Person [name=ddd, gender=female, age=22]
Person [name=fff, gender=female, age=25]
执行男性的过滤器
Person [name=aaa, gender=male, age=14]
Person [name=bbb, gender=male, age=70]
Person [name=ccc, gender=male, age=19]

组合模式(Composite Pattern)

组合模式有时又叫作部分-整体模式,它是一种将对象组合成树状的层次结构的模式,用来表示“部分-整体”的关系,使用户对单个对象和组合对象具有一致的访问性。

优点
  • 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码
  • 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”
缺点
  • 设计较复杂,客户端需要花更多时间理清类之间的层次关系
  • 不容易限制容器中的构件
  • 不容易用继承的方法来增加构件的新功能

由于组合模式比较复杂,我们先来认识一下实现组合模式的构件

  • 抽象构件(Component)角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。
  • 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于实现抽象构件角色中 声明的公共接口。
  • 树枝构件(Composite)角色:是组合中的分支节点对象,它有子节点。它实现了抽象构件角色中声明的接口,它的主要作用是存储和管理子部件。
透明式的组合模式和安全式的组合模式的区别
  • 透明方式:在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。
  • 安全方式:在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。
示例

我们演示一下透明式的组合模式的实现

先创建一个抽象构件

//抽象构件
public interface Component {

	void add(Component component);
	void remove(Component component);
	//实现自定义的业务逻辑
	void operation();
}

实现树枝构件

//树枝构件
public class Composite implements Component {

	private String name;
	private List<Component> children;
	
	public Composite(String name) {
		this.name = name;
		children=new ArrayList<Component>();
	}
	
	@Override
	public void add(Component component) {
		children.add(component);
	}

	@Override
	public void remove(Component component) {
		children.remove(component);
	}

	@Override
	public void operation() {
		System.out.println("树枝构件" + name + "被访问");
		
		for (Component component : children) {
			component.operation();
		}
	}

}

实现叶子构件

public class Leaf implements Component {

	private String name;
	
	public Leaf(String name) {
		this.name = name;
	}
	
	@Override
	public void add(Component component) {}

	@Override
	public void remove(Component component) {}

	@Override
	public void operation() {
		System.out.println("叶子节点" + name + "被访问");
	}

}

测试一下

public class Test {

	public static void main(String[] args) {
		//定义一个根节点
		Component composite1 = new Composite("根节点1");
		
		Component leaf1 = new Leaf("叶子节点1");
		Component composite2 = new Composite("根节点2");
		Component composite3 = new Composite("根节点3");
		
		composite1.add(leaf1);
		composite1.add(composite2);
		composite1.add(composite3);
		
		Component leaf2 = new Leaf("叶子节点2");
		Component leaf3 = new Leaf("叶子节点3");
		composite3.add(leaf2);
		composite3.add(leaf3);
		
		//实现遍历
		composite1.operation();
	}
}

结果如下

树枝构件根节点1被访问
叶子节点叶子节点1被访问
树枝构件根节点2被访问
树枝构件根节点3被访问
叶子节点叶子节点2被访问
叶子节点叶子节点3被访问

我的下一篇设计模式博客:设计模式详解(4)-- 结构型模式详解下

参考: https://www.cnblogs.com/V1haoge/p/6479118.html
https://www.cnblogs.com/chenssy/p/3317866.html
http://www.runoob.com/design-pattern/filter-pattern.html
http://c.biancheng.net/view/1373.html

猜你喜欢

转载自blog.csdn.net/Geffin/article/details/89345150
今日推荐