适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。
意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
**主要解决:**主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。
何时使用:
**如何解决:**继承或依赖(推荐)。
**关键代码:**适配器继承或依赖已有的对象,实现想要的目标接口。
应用实例:
优点:
缺点:
1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。
2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
**使用场景:**有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。
**注意事项:**适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。
AdvancedMediaPlayer及其子类Mp4 Vlc
public interface AdvancedMediaPlayer {
public void playVlc(String file);
public void playMp4(String file);
}
class Mp4 implements AdvancedMediaPlayer{
@Override
public void playVlc(String file) {}
@Override
public void playMp4(String file) {
System.out.println("Playing mp4--"+"fileName: "+file);
}
}
class Vlc implements AdvancedMediaPlayer{
@Override
public void playVlc(String file) {
System.out.println("Playing vlc--"+"fileName: "+file);
}
@Override
public void playMp4(String file) {}
}
MediaPlayer和子类MediaAdapter适配器 子类 OldPlayer
public interface MediaPlayer {
public void play(String type,String file);
}
class MediaAdapter implements MediaPlayer{
private AdvancedMediaPlayer advancedMediaPlayer;
public MediaAdapter(String type){
if(type.equalsIgnoreCase("mp4")){
advancedMediaPlayer = new Mp4();
} else if (type.equalsIgnoreCase("vlc")) {
advancedMediaPlayer = new Vlc();
}else{
System.out.println("该格式不支持");
}
}
@Override
public void play(String type, String file) {
if(type.equalsIgnoreCase("mp4")){
advancedMediaPlayer.playMp4(file);
}else if (type.equalsIgnoreCase("vlc")){
advancedMediaPlayer.playVlc(file);
}else{
System.out.println("该格式不支持"+type);
}
}
}
class OldPlayer implements MediaPlayer{
private MediaAdapter mediaAdapter;
@Override
public void play(String type, String file) {
if(type.equalsIgnoreCase("mp3")){//支持格式
System.out.println("Playing mp3--"+"fileName: "+file);
} else if (type.equalsIgnoreCase("mp4") || type.equalsIgnoreCase("vlc") ) {
mediaAdapter = new MediaAdapter(type);
mediaAdapter.play(type,file);
}else {
System.out.println("此格式不支持"+type);
}
}
}
Client用户端调用
public class Client extends OldPlayer {
public static void main(String[] args) {
OldPlayer oldPlayer = new OldPlayer();
oldPlayer.play("mp3","a.txt");
oldPlayer.play("mp4","a.txt");
oldPlayer.play("vlc","a.txt");
oldPlayer.play("error","a.txt");
}
}
MVC中的应用
DispatcherServlet中的doDispatch方法,是将请求分发到具体的controller,因为存在很多不同类型的controller,常规处理是用大量的if…else…,来判断各种不同类型的controller,如下这样
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类,这两种类型的类可被结构化改变而互不影响。
桥接模式的目的是将抽象与实现分离,使它们可以独立地变化,该模式通过将一个对象的抽象部分与它的实现部分分离,使它们可以独立地改变。它通过组合的方式,而不是继承的方式,将抽象和实现的部分连接起来。
我们通过下面的实例来演示桥接模式(Bridge Pattern)的用法。其中,可以使用相同的抽象类方法但是不同的桥接实现类,来画出不同颜色的圆。
**意图:**将抽象部分与实现部分分离,使它们都可以独立的变化。
**主要解决:**在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。
**何时使用:**实现系统可能有多个角度分类,每一种角度都可能变化。
**如何解决:**把这种多角度分类分离出来,让它们独立变化,减少它们之间耦合。
**关键代码:**抽象类依赖实现类。
优点: 1、抽象和实现的分离。 2、优秀的扩展能力。 3、实现细节对客户透明。
**缺点:**桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
使用场景:
**注意事项:**对于两个独立变化的维度,使用桥接模式再适合不过了。
以下是桥接模式的几个关键角色:
我们有一个作为桥接实现的 DrawAPI 接口和实现了 DrawAPI 接口的实体类RedCircle、GreenCircle。Shape 是一个抽象类,将使用 DrawAPI 的对象。Client类使用 Shape 类来画出不同颜色的圆。
**创建桥接实现接口DrawAPI和其实现子类RedCircle、GreenCircle**
public interface DrawAPI {
public void drawCircle(int radius,int x,int y);
}
class GreenCircle implements DrawAPI{
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("正在绘制半径为"+radius+"坐标为:x="+x+" y="+y+"绿色的圆");
}
}
class RedCircle implements DrawAPI{
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("正在绘制半径为"+radius+"坐标为:x="+x+" y="+y+"红色的圆");
}
}
使用 DrawAPI 接口创建抽象类 *Shape 和其实现子类Circle*
public abstract class Shape {
protected DrawAPI drawAPI;
protected Shape(DrawAPI drawAPI){
this.drawAPI = drawAPI;
}
public abstract void draw();
}
class Circle extends Shape{
private int x,y,radius;
protected Circle(int radius,int x,int y,DrawAPI drawAPI) {
super(drawAPI);
this.x = x;
this.y = y;
this.radius = radius;
}
@Override
public void draw() {
drawAPI.drawCircle(radius,x,y);
}
}
Client使用 Shape 和 DrawAPI 类画出不同颜色的圆
public class Client {
public static void main(String[] args) {
new Circle(10,10,10,new GreenCircle()).draw();
new Circle(10,10,10,new RedCircle()).draw();
}
}
总结
优点
缺点
过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。这种类型的设计模式属于结构型模式,它结合多个标准来获得单一标准。
优点:
缺点:
这绝对是我见过的最没存在感的设计模式了。
应用案例:
我们将创建一个 Person 对象、Criteria 接口和实现了该接口的实体类,来过滤 Person 对象的列表。CLient类使用 Criteria 对象,基于各种标准和它们的结合来过滤 Person 对象的列表。
创建一个类Person,在该类上应用标准。
public class Person {
private String name;
private String gender;
private String maritalStatus;
public Person(String name, String gender, String maritalStatus) {
this.name = name;
this.gender = gender;
this.maritalStatus = maritalStatus;
}
public String getName() {
return name;
}
public String getGender() {
return gender;
}
public String getMaritalStatus() {
return maritalStatus;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", maritalStatus='" + maritalStatus + '\'' +
'}';
}
}
为标准创建一个接口Criteria 和其实现子类FemaleCriteria MaleCriteria SingleCriteria
public interface Criteria {
public List<Person> meetCriteria(List<Person> personList);
}
class FemaleCriteria implements Criteria{
@Override
public List<Person> meetCriteria(List<Person> personList) {
List<Person> femalePersons =new ArrayList<>();
for (Person person:personList) {
if (person.getGender().equalsIgnoreCase("female")){
femalePersons.add(person);
}
}
return femalePersons;
}
}
class MaleCriteria implements Criteria{
@Override
public List<Person> meetCriteria(List<Person> personList) {
List<Person> malePersons =new ArrayList<>();
for (Person person:personList) {
if (person.getGender().equalsIgnoreCase("male")){
malePersons.add(person);
}
}
return malePersons;
}
}
class SingleCriteria implements Criteria{
@Override
public List<Person> meetCriteria(List<Person> personList) {
List<Person> singlePersons =new ArrayList<>();
for (Person person:personList) {
if (person.getMaritalStatus().equalsIgnoreCase("single")){
singlePersons.add(person);
}
}
return singlePersons;
}
}
实现Criteria并组合标准类AndCriteria OrCriteria
public class AndCriteria implements Criteria{
private Criteria criteria;
private Criteria otherCriteria;
public AndCriteria(Criteria criteria, Criteria otherCriteria) {
this.criteria = criteria;
this.otherCriteria = otherCriteria;
}
@Override
public List<Person> meetCriteria(List<Person> personList) {
List<Person> firstCriteriaPersons = criteria.meetCriteria(personList);
List<Person> secondCriteriaPersons = otherCriteria.meetCriteria(firstCriteriaPersons);
return secondCriteriaPersons;
}
}
class OrCriteria implements Criteria{
private Criteria criteria;
private Criteria otherCriteria;
public OrCriteria(Criteria criteria, Criteria otherCriteria) {
this.criteria = criteria;
this.otherCriteria = otherCriteria;
}
@Override
public List<Person> meetCriteria(List<Person> personList) {
List<Person> firstCriteriaPersons = criteria.meetCriteria(personList);
List<Person> secondCriteriaPersons = otherCriteria.meetCriteria(firstCriteriaPersons);
for(Person person:firstCriteriaPersons){
if(!secondCriteriaPersons.contains(person)){
secondCriteriaPersons.add(person);
}
}
return secondCriteriaPersons;
}
}
Client端调用Criteria
public class Client {
public static void main(String[] args) {
Person person1= new Person("mike", "male", "single");
Person person2= new Person("mary", "female", "no");
Person person3= new Person("scary", "female", "single");
Person person4= new Person("tom", "male", "no");
Person person5= new Person("amy", "female", "single");
List<Person> personList = new ArrayList<>();
personList.add(person1);
personList.add(person2);
personList.add(person3);
personList.add(person4);
personList.add(person5);
FemaleCriteria femaleCriteria = new FemaleCriteria();
MaleCriteria maleCriteria = new MaleCriteria();
SingleCriteria singleCriteria = new SingleCriteria();
AndCriteria femaleAndSingle = new AndCriteria(femaleCriteria, singleCriteria);
OrCriteria maleOrSingle = new OrCriteria(maleCriteria, singleCriteria);
List<Person> personList1 = femaleAndSingle.meetCriteria(personList);
List<Person> personList2 = maleOrSingle.meetCriteria(personList);
show(personList1);
System.out.println("================================");
show(personList2);
}
static void show(List<Person> personList){
for (Person person:personList){
System.out.println(person);
}
}
}
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于==结构型模式,==它创建了对象组的树形结构。
这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
**意图:**将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
**主要解决:**它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
何时使用:
**如何解决:**树枝和叶子实现统一接口,树枝内部组合该接口。
**关键代码:**树枝内部组合该接口,并且含有内部属性 List,里面放 Component。
应用实例:
优点: 1、高层模块调用简单。 2、节点自由增加。
**缺点:**在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
**使用场景:**部分、整体场景,如树形菜单,文件、文件夹的管理。
我们有一个类Employee,该类被当作组合模型类。Client 类使用 Employee 类来添加部门层次结构,并打印所有员工
被当作组合模型类Employee
public class Employee {
private String name;
private String dept;
private int salary;
private List<Employee> subordinates = new ArrayList<>();
public Employee(String name, String dept, int salary) {
this.name = name;
this.dept = dept;
this.salary = salary;
}
public void add(Employee employee){
subordinates.add(employee);
}
public void remove(Employee employee){
subordinates.remove(employee);
}
public List<Employee> getSubordinates(){
return this.subordinates;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", subordinates=" + subordinates +
'}';
}
}
Client组合Employee
public class Client {
public static void main(String[] args) {
Employee CEO = new Employee("CEO", "CBD", 10000);
Employee CFO = new Employee("CFO", "CFO", 20000);
Employee Mack = new Employee("Mack", "Mack", 15000);
Employee employee1 = new Employee("employee1", "employee1", 1000);
Employee employee2 = new Employee("employee2", "employee2", 1000);
Employee employee3 = new Employee("employee3", "employee3", 1000);
Employee employee4 = new Employee("employee4", "employee4", 1000);
CEO.add(CFO);
CEO.add(Mack);
Mack.add(employee1);
Mack.add(employee2);
CFO.add(employee3);
CFO.add(employee4);
List<Employee> subordinates = CEO.getSubordinates();
System.out.println(CEO);
for (Employee employee:subordinates){
System.out.println(employee);
for(Employee employee5:employee.getSubordinates()){
System.out.println(employee5);
}
System.out.println("----------------");
}
}