结构型模式
结构型模式描述如何组织类和对象以及组成更大的结构,结构型类模式采用继承机制来组合接口和实现,结构型对象模式采用组合聚合来组合对象以实现功能,可以在运行时刻改变对象组合的关系,具有更大的灵活性。
- 适配器模式(Adapter Pattern)
- 桥接模式(Bridge Pattern)
- 过滤器模式(Filter Pattern)
- 组合模式(Composite Pattern)
- 装饰器模式(Decorator Pattern)
- 外观模式(Facade Pattern)
- 享元模式(Flyweight Pattern)
适配型模式(Adapter Pattern)
适配器模式把一个类的接口变成客户端所期待的另一种接口,从而使原先接口不匹配而无法在一起工作的两个类可以在一起工作
适配器的用途:用电器做例子,笔记本电脑的插头一般都是三相的,而有的电源插座只有两相,电源插座与笔记本插头不匹配使得笔记本电脑无法使用,这时候一个三相到两相的转换器(适配器)就可以解决这个问题。我们在生活当中可以遇到很多很多的转化器。这些转换器就是帮助我们将两个不匹配的东西匹配到一起。
//插座
public interface Socket {
//提供电
public void provideElectricity();
//告诉其他对象,自己的插座是几相的
public int getPin();
}
//三相插座
public class ThreePin implements Socket{
@Override
public void provideElectricity() {
System.out.println("我是三角插线板,提供电");
}
//返回引脚数量
@Override
public int getPin() {
return 3;
}
}
//电脑先设置插座,只有两相的插座才可以启动
public class Computer {
//设置插座
Socket socket;
public void setSocket(Socket socket){
this.socket = socket;
}
public void start(){
if(socket.getPin()==3){
System.out.println("电脑:我需要2个引脚的插线板");
}else if(socket.getPin()==2){
socket.provideElectricity();
System.out.println("电脑:我得到了2个引脚的插线板");
System.out.println("电脑:我插上电开始启动了");
}
}
}
//适配器提供两相的插座对外。调用三相的插座产生电
public class Adapter extends ThreePin implements Socket{
@Override
public void provideElectricity() {
System.out.println("我是转换器:我调用ThreePin产生电");
super.provideElectricity();
}
@Override
public int getPin() {
return 2;
}
}
public class Demo {
public static void main(String[] args){
Computer computer=new Computer();
Socket threePin =new ThreePin();
computer.setSocket(threePin);
computer.start();
//Adapter adapter=new Adapter();
// computer.setSocket(adapter);
//computer.start();
}
}
输出结果 电脑:我需要2个引脚的插线板
电脑直接用三相的插座。电脑无法启动
public class Demo {
public static void main(String[] args){
Computer computer=new Computer();
//Socket threePin =new ThreePin();
//computer.setSocket(threePin);
//computer.start();
Adapter adapter=new Adapter();
computer.setSocket(adapter);
computer.start();
}
}
电脑使用适配器
输出结果:
我是转换器:我调用ThreePin产生电
我是三角插线板,提供电
电脑:我得到了2个引脚的插线板
电脑:我插上电开始启动了
正确启动
分析:当电脑和三相引脚都存在的时候,而我们又都不想修改电脑和插座类的时候,我们想让电脑启动起来。但是电脑只能使用两相的引脚。所以这个时候我们创建一个Adapter。通过适配器去转换使得电脑可以正常的启动起来。这就是适配器模式的好处。适配器模式尽量少用。过多的使用会使得系统非常零乱,不易对整体把握。毕竟在生活中我们也更愿意2相接口的电脑去插两相的插板。
桥接模式(Bridge Pattern)
桥接模式:是用于把抽象化与实现化解耦,使得二者可以独立变化。这种模式设计到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可以被结构化改变而不互相影响。对于不希望使用继承或因为多层次继承导致类的个数急剧增加的系统,使用桥接模式尤为适用,且一个类存在两个独立变化的维度,且两个维度都需要进行拓展。
public abstract class Shape { protected Color color; public void setColor(Color color){ this.color = color; } public abstract void draw(); } public class Circle extends Shape{ @Override public void draw() { color.draw("圆形"); } } public class Rectangle extends Shape{ @Override public void draw() { color.draw("四边形"); } } public interface Color { public void draw(String shape); } public class Black implements Color{ @Override public void draw(String shape) { System.out.println("颜色是黑色的"+shape); } } public class White implements Color{ @Override public void draw(String shape) { System.out.println("颜色是白色的"+shape); } } public class Demo { public static void main(String[] args){ Shape shape=new Circle(); Color black=new Black(); shape.setColor(black); shape.draw(); Color white = new White(); shape.setColor(white); shape.draw(); } } 输出结果: 颜色是黑色的圆形 颜色是白色的圆形
分析:通过采用桥接模式,我们可以组合出各种类型的对象来。而不是通过继承去实现很多个子类。
组合模式(Composite Pattern)
组合模式,又叫部分整体模式。用于把一组相识的对象当做一个单一的对象。组合模式依据树型结构来组合对象,用来表示部分以及整体的层次。这种模式提供了保护自己对象组的类,并提供了修改相同对象组的方式。
//XX 党 public abstract class CCP { String name; public CCP(String name){ this.name = name; } public CCP(){ } public String getName() { return name; } public void setName(String name) { this.name = name; } protected abstract void add(CCP ccp); protected abstract void remove(CCP ccp); protected abstract void display(int depth); } public class CCPBranch extends CCP { List<CCP> branches= new ArrayList<>(); public CCPBranch(String name){ super(name); } @Override protected void add(CCP ccp) { branches.add(ccp); } @Override protected void remove(CCP ccp) { branches.remove(ccp); } @Override protected void display(int depth) { StringBuilder sb = new StringBuilder(); for(int i=0;i<depth;i++){ sb.append("-"); } System.out.println(sb.toString()+this.getName()); for(CCP ccp:branches){ ccp.display(depth+1); } } } public class Demo { public static void main(String[] args){ CCP ccp=new CCPBranch("中国共产党"); CCP chongqing = new CCPBranch("重庆市委"); CCP sichuan = new CCPBranch("四川省委"); CCP chengdu =new CCPBranch("成都市委"); ccp.add(chongqing); ccp.add(sichuan); sichuan.add(chengdu); ccp.display(0); } } 输出结果 中国共产党 -重庆市委 -四川省委 --成都市委分析:创建了CCP抽象类。然后创建了一个CCPbranch的类。然后我们new了4个党的支部。通过按照组织的结果去添加子组织。就能很快和方便的构建出组织结构树。组合模式在我们对有树形分叉的这种结构中可以发挥到很好的作用。减少客户端的代码。
过滤器模式(Filter Pattern)
通过不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。
//定义Person类 public class Person { private String name; private String gender; private String nationality; public Person(String name,String gender,String nationality){ this.name = name; this.gender = gender; this.nationality = nationality; } 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 String getNationality() { return nationality; } public void setNationality(String nationality) { this.nationality = nationality; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", gender='" + gender + '\'' + ", nationality='" + nationality + '\'' + '}'; } } //Criteria接口 public interface Criteria { public List<Person> filter(List<Person> person); } //性别 public class GenderCriteria implements Criteria{ String gender; public GenderCriteria(String gender){ this.gender = gender; } @Override public List<Person> filter(List<Person> input) { List<Person> outPut = new ArrayList<>(); for(Person temp:input){ if(temp.getGender().equalsIgnoreCase(gender)){ outPut.add(temp); } } return outPut; } } //国籍 public class NationCriteria implements Criteria{ private String nationality; public NationCriteria(String nationality){ this.nationality = nationality; } @Override public List<Person> filter(List<Person> input) { List<Person> output =new ArrayList<>(); for(Person person:input){ if (person.getNationality().equalsIgnoreCase(nationality)){ output.add(person); } } return output; } } //Add public class AddCriteria implements Criteria{ private Criteria criteria; private Criteria otherCriteria; public AddCriteria(Criteria criteria,Criteria otherCriteria){ this.criteria =criteria; this.otherCriteria = otherCriteria; } @Override public List<Person> filter(List<Person> input) { List<Person> criteriaOutput = criteria.filter(input); return otherCriteria.filter(criteriaOutput); } } public 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> filter(List<Person> input) { List<Person> criteriaOutput = criteria.filter(input); List<Person> otherCriteriaOutput = criteria.filter(input); HashSet<Person> set =new HashSet<>(); set.addAll(criteriaOutput); set.addAll(otherCriteriaOutput); return new ArrayList<>(set); } } public class Demo { public static void main(String[] args){ List<Person> persons = new ArrayList<>(); persons.add(new Person("一一","男","中国")); persons.add(new Person("二二","女","中国")); persons.add(new Person("三三","女","美国")); persons.add(new Person("思思","男","中国")); persons.add(new Person("呜呜","女","日本")); persons.add(new Person("六六","女","中国")); persons.add(new Person("琪琪","男","澳大利亚")); persons.add(new Person("巴巴","男","美国")); Criteria male =new GenderCriteria("男"); Criteria china =new NationCriteria("中国"); Criteria chinamale = new AddCriteria(male,china); Criteria chinaOrMale = new OrCriteria(male,china); System.out.println("Male"); print(male.filter(persons)); System.out.println("China"); print(china.filter(persons)); System.out.println("ChinaMale"); print(chinamale.filter(persons)); System.out.println("ChinaOrMale"); print(chinaOrMale.filter(persons)); } public static void print(List<Person> input){ for(Person person:input){ System.out.println(person.toString()); } } } //输出结果 Male Person{name='一一', gender='男', nationality='中国'} Person{name='思思', gender='男', nationality='中国'} Person{name='琪琪', gender='男', nationality='澳大利亚'} Person{name='巴巴', gender='男', nationality='美国'} China Person{name='一一', gender='男', nationality='中国'} Person{name='二二', gender='女', nationality='中国'} Person{name='思思', gender='男', nationality='中国'} Person{name='六六', gender='女', nationality='中国'} ChinaMale Person{name='一一', gender='男', nationality='中国'} Person{name='思思', gender='男', nationality='中国'} ChinaOrMale Person{name='一一', gender='男', nationality='中国'} Person{name='思思', gender='男', nationality='中国'} Person{name='巴巴', gender='男', nationality='美国'} Person{name='琪琪', gender='男', nationality='澳大利亚'}分析:创建了很多的Person,然后创建了性别和国籍的filter。然后又将这两种filter使用add和or组合起来了。最后调用filter进行过滤。可以很清楚的看到我们的输入和我们预期的结果是相同的。当需要添加filter。各种filter进行组合的时候。这样的写法是非常方便的。
装饰器模式(Decorator Pattern)
允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
//创建接口英雄 public interface Hero { void hasSkill(); } //剑圣 public class BladeMaster implements Hero { private String skillQ; private String skillW; public BladeMaster(String skillQ,String skillW){ this.skillQ = skillQ; this.skillW = skillW; } @Override public void hasSkill() { System.out.print("我是剑圣 I have skill " + skillQ +","+skillW); } } public class IntensifyBlade implements Hero{ private Hero hero; private String skillE; public IntensifyBlade(Hero hero,String skillE){ this.hero = hero; this.skillE = skillE; } @Override public void hasSkill() { System.out.println(); System.out.print("我是加强版剑圣 "); this.hero.hasSkill(); System.out.println(", "+skillE); } } public class Demo { public static void main(String[] args){ Hero blade = new BladeMaster("小剑","大剑"); blade.hasSkill(); Hero intensifyBlade =new IntensifyBlade(blade,"绝招"); intensifyBlade.hasSkill(); } } 输出结果 我是剑圣 I have skill 小剑,大剑 我是加强版剑圣 我是剑圣 I have skill 小剑,大剑, 绝招分析:首先创建了一个剑圣类。有用小剑和大剑的技能。然后创建了一个加强版的健身类,对剑圣的能力进行了拓展,拥有了更加厉害的技能。装饰器模式可以在不改变原有的类的情况下,对原先类进行拓展。
外观模式(Facade Pattern)
隐藏系统的复杂性,并向客户端提供一个客户端可以访问的接口。这种模式设计到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的调用。
public interface Skill { void casting(); } public class SkillQ implements Skill{ public void casting(){ System.out.println("施放Q技能"); } } public class SkillW { public void casting(){ System.out.println("施放W技能"); } } public class SkillMaker { private SkillQ skillQ; private SkillW skillW; public SkillMaker(){ this.skillQ = new SkillQ(); this.skillW = new SkillW(); } public SkillQ getSkillQ() { return skillQ; } public void setSkillQ(SkillQ skillQ) { this.skillQ = skillQ; } public SkillW getSkillW() { return skillW; } public void setSkillW(SkillW skillW) { this.skillW = skillW; } public void castingQ(){ skillQ.casting(); } public void castingW(){ skillW.casting(); } } public class Demo { public static void main(String[] args){ SkillMaker skillMaker=new SkillMaker(); skillMaker.castingQ(); skillMaker.castingW(); } }享元模式(Flyweight Pattern)
主要用于减少创建对象的数量。以减少内存占用和提高性能。享原模式尝试采用现有的同类对象,如何未找到匹配的对象,则创建新的对象。在Java的String就是这样的,如果有则返回,如果没有则创建一个字符串保存在字符串缓存池里面。优点可以大大的减少对象的创建,降低系统的内存,使得效率提高。
public interface Shape { void draw(); } public class Circle implements Shape{ private String color; private int x; private int y; private int radius; public Circle(String color){ this.color = color; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public int getRadius() { return radius; } public void setRadius(int radius) { this.radius = radius; } @Override public String toString() { return "Circle{" + "color='" + color + '\'' + ", x=" + x + ", y=" + y + ", radius=" + radius + '}'; } @Override public void draw() { System.out.println(this.toString()); } } public class Factory { private static final HashMap<String,Shape> circleMap =new HashMap<>(); public static Shape getShape(String color){ Circle circle =(Circle)circleMap.get(color); if(circle == null){ circle =new Circle(color); circleMap.put(color,circle); System.out.println("Create new circle"); } return circle; } } public class Demo { private static final String colors[] = {"Red","Green","Blue","White","Black"}; public static void main(String[] args){ for(int i=0;i<20;++i){ Circle circle = (Circle)Factory.getShape(getRandomColor()); circle.setX(getRandomX()); circle.setY(getRandomY()); circle.setRadius(100); circle.draw(); } } public static String getRandomColor(){ return colors[(int)(Math.random()*100%colors.length)]; } public static int getRandomX(){ return (int)(Math.random()*100); } public static int getRandomY(){ return (int)(Math.random()*100); } }代理模式(Proxy Pattern)
一个类代表另外一个类的功能,在代理模式中,我们创建具有现在对象的对象。以便提供对外界的接口。
public interface Worker { public void writeDocument(); } public class Boss implements Worker{ private String name; public Boss(String name){ this.name = name; } @Override public void writeDocument() { System.out.println("I am "+name); System.out.println("Boss write document"); } } public class Secretary implements Worker{ private Boss boss; private String name; public Secretary(String name){ this.name = name; } @Override public void writeDocument() { System.out.println("I am "+name); System.out.println("I help boss write document"); if(boss == null){ boss =new Boss("老板"); } boss.writeDocument(); } } public class Demo { public static void main(String[] args){ Boss boss=new Boss("老板"); boss.writeDocument(); Secretary secretary=new Secretary("秘书"); secretary.writeDocument(); } }分析:boss和secretary都是worker。老板如果要写文档可以直接写文档。但是我们可以调用秘书去帮助老板写文档。
注:本博客所用的实例代码都会放在Github供大家下载学习。
地址:https://github.com/standup-jb/DesignPattern.git
知乎主页:点击关注我知乎
如果可以愿意分享自己的见解或者添加更多更好的实例代码,可以联系我。谢谢。
相关博客:设计模式:创建型模式(一)