设计模式简介
设计模式代表了最佳实现,是软件开发过程中面临的一般问题的解决方案。
设计模式的类型
总共有23种设计模式,可分为三大类:创建型模式、结构型模式、行为型模式。
-
创建型模式:提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用new运算符直接实例化对象。这使得程序在判断对某个给定实例需要创建哪些实例对象时更加灵活。
包括:工厂模式(Factory Pattern)、抽象工厂模式(Abstract Factory Pattern)、单例模式(Singleton Pattern)、建造者模式(Builder Pattern)、原型模式(Prototype Pattern); -
结构型模式:这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
包括:适配器模式(Adapter Pattern)、桥接模式(Bridge Pattern)、过滤器模式(Filter、Criteria Pattern)、组合模式、装饰器模式、外观模式、享元模式、代理模式。 -
行为型模式:这些设计模式特别关注对象之间的通信;
包括:责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、空对象模式、策略模式、模板模式、访问者模式。
设计模式的六大原则
-
开闭原则
对扩展开放,对修改关闭,在程序需要进行扩展的时候,不能去修改原有代码; -
里氏代换原则
任何基类出现的地方,子类一定可以出现。 -
依赖倒转原则
针对接口编程,依赖抽象而不依赖具体; -
接口隔离原则
使用多个隔离的接口比使用单个接口要好,降低类之间的耦合度。 -
迪米特法则,又称为最少知道原则
一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。 -
合成复用原则
尽量使用合成聚合的方式,而不是使用继承;
单例模式(Singleton)
概述
涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,这个类提供一种访问其唯一对象的方式,可以直接访问呢,不需要实例化该类的对象。
-
解决问题:一个全局使用的类频繁地创建与销毁;
-
何时使用:当你想控制实例数目,节省系统资源的时候;
-
优点:减少了内存的开销,不用再频繁的创建和销毁实例;避免对资源的多重占用。
-
缺点:没有接口、不能继承、于单一职责原则冲突。
-
方法一:饿汉式单例(一开始就创建好实例)
public class SingleInstance {
//让构造器私有,别的类就无法创建这个类的对象
private SingleInstance() {
}
//在自己类里面创建实例
private static final SingleInstance ME=new SingleInstance();
//获取唯一实例
public static SingleInstance getInstance(){
return ME;
}
}
三步:让别人不能创建实例,自己创建实例,定义方法返回自己创建的实例。
- 方法二:懒汉式(用的时候再创建实例,线程安全)
public class SingleInstance2 {
//私有化构造器
private SingleInstance2() {
}
//只定义实例,而不创建
private static SingleInstance2 ME;
//定义方法,返回实例,要是第一次就创建实例并返回,否则不创建
//注意线程同步
public static synchronized SingleInstance2 getLinstance(){
if(ME==null){
ME=new SingleInstance2();
}
return ME;
}
}
- 方法三:用枚举类实现单例,属于饿汉式单例
最佳方法,自动支持序列化机制,绝对防止多次实例化;
public enum SingletonEnum {
ME;
public void otherMethod(){}
}
- 方法四:双检锁/双重检验锁(DCL)
package com.westos.Demo;
public class Singleton2 {
//定义实例对象,
// 并且用volatile修饰(一重锁:保证了线程之间操作的可见性和指令执行的有序性)
private volatile static Singleton2 singleton2;
private Singleton2(){}
public static Singleton2 getSingleton2(){
if(singleton2==null){
//二重锁,保证了线程同步,和原子性
synchronized (Singleton2.class){
if(singleton2==null){
singleton2=new Singleton2();
}
}
}
return singleton2;
}
}
- 方法五:登记式/静态内部类(属于懒汉式)
这种方式能达到双检锁一样的动销,但实现更简单。
不立即实例化SingletonInterClass类,而是在调用 getIntance()方法时先加载静态内部类SingtonHolder,从而实例化对象;
public class SingletonInterClass {
private static class SingtonHolder{
private static final SingletonInterClass ME=new SingletonInterClass();
}
private SingletonInterClass(){};
public static SingletonInterClass getIntance(){
return SingtonHolder.ME;
}
}
享元模式(Flyweight)
主要用于减少创建对象的数量,以减少内存占用和性能提高。尝试重用现有的同类对象,如果未找到匹配的对象,则创建新的对象。
- 优点:大大减少对象的创建,降低系统的内存,使效率提高;
- 缺点:提高了系统的复杂度,需要分离出外部和内部状态。
使用Hashmap存储对象,当在需要创建新的对象时,先判断Hashmap中是否已经存在了该对象,如果存在就返回已经存在的对象,否则创建新的对象并放入Hashmap中。
package com.westos.Demo;
import java.util.HashMap;
public class FlyweightTest {
private static HashMap<Object,FlyweightTest> map=new HashMap<>();
public static FlyweightTest getInstance(Object obj){
if(map.containsKey(obj)){
return map.get(obj);
}else {
FlyweightTest fly= new FlyweightTest();
map.put(obj,fly);
return fly;
}
}
}
public class Flyweight1 {
public static void main(String[] args) {
System.out.println(FlyweightTest.getInstance(1)==FlyweightTest.getInstance(1));
System.out.println(FlyweightTest.getInstance(2)==FlyweightTest.getInstance(1));
}
}
原型模式(Prototype)
用于创建重复对象,同时又能保证性能。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。
如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例,但不是同一个实例,只是属性一样;
- 实现Cloneable接口
- 重写clone方法
package com.westos.Demo;
public class PrototypeTest implements Cloneable{
private String name;
private String sex;
private String city;
private int age;
public PrototypeTest(String name, String sex, String city, int age) {
this.name = name;
this.sex = sex;
this.city = city;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setCity(String city) {
this.city = city;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public String getCity() {
return city;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "PrototypeTest{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", city='" + city + '\'' +
", age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
package com.westos.Demo;
public class CloneTest{
public static void main(String[] args) throws CloneNotSupportedException {
PrototypeTest p1 = new PrototypeTest("小明", "男", "北京", 18);
PrototypeTest p2 = (PrototypeTest)p1.clone();
System.out.println(p2);
//克隆出来的不是同一个对象
System.out.println(p1==p2);
p2.setName("小红");
p2.setAge(5);
System.out.println(p2);
}
}
深拷贝与浅拷贝
- 浅拷贝:克隆是浅拷贝,只拷贝原来对象的基本数据类型和引用数据类型的引用,而不拷贝对象本身,也就是拷贝出来的引用还是指向原来的对象。
- 深拷贝:所有的内容都复制全新的。将对象序列化和反序列化,深拷贝可以用反序列化来完成。
深拷贝
package com.westos.Demo;
import java.io.*;
import java.util.Date;
public class PrototypeTest implements Cloneable,Serializable {
private String name;
private String sex;
private String city;
private int age;
private Date birth;
public PrototypeTest(String name, String sex, String city, int age, Date birth) {
this.name = name;
this.sex = sex;
this.city = city;
this.age = age;
this.birth = birth;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public void setName(String name) {
this.name = name;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setCity(String city) {
this.city = city;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public String getCity() {
return city;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "PrototypeTest{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", city='" + city + '\'' +
", age=" + age +
", birth=" + birth +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
//创建字节数组输出流
ByteArrayOutputStream os = new ByteArrayOutputStream();
//把当前对象写入输出流
try {
new ObjectOutputStream(os).writeObject(this);
//拿到字节数组
byte[] bytes = os.toByteArray();
//反序列化成新对象
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
//传给对象输入流
return new ObjectInputStream(is).readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
package com.westos.Demo;
import java.util.Date;
public class CloneTest{
public static void main(String[] args) throws CloneNotSupportedException {
PrototypeTest p1 = new PrototypeTest("小明", "男", "北京", 18,new Date());
PrototypeTest p2 = (PrototypeTest)p1.clone();
System.out.println(p2);
//克隆出来的不是同一个对象
System.out.println(p1==p2);
p2.setName("小红");
p2.getBirth().setTime(28);
System.out.println(p2);
System.out.println(p1);
}
}
深拷贝结果
浅拷贝结果
可以看到由于拷贝的只是地址当改变小红的生日的时候,小明的生日也被改变。
建造者模式(Builder)
使用多个简单对象一步一步构建成一个复杂对象。
- 意图:讲一个复杂的构建与其表示相分离,使用同样的构建过程可以创建不同的表示。
- 优点:建造者独立,易扩展;便于控制细节风险;
- 缺点:产品必须有共同点,范围有限制;如内部变化复杂,会有很多的建造了类。
package com.westos.Demo;
public class BuilderTest {
private String name;
private String sex;
private String city;
private int age;
public BuilderTest(String name, String sex, String city, int age) {
this.name = name;
this.sex = sex;
this.city = city;
this.age = age;
}
//建造器
public static class Builder{
private String name;
private String sex="男";
private String city="上海";
private int age;
//设置属性,将传进来的值与对象绑定,返回这个对象以便后面方法连续调用
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setSex(String sex) {
this.sex = sex;
return this;
}
public Builder setCity(String city) {
this.city = city;
return this;
}
public Builder setAge(int age) {
this.age = age;
return this;
}
//等信息收集齐了,返回创建返回完整对象
public BuilderTest builder(){
return new BuilderTest(this.name,this.sex,this.city,this.age);
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public String getCity() {
return city;
}
public int getAge() {
return age;
}
}
@Override
public String toString() {
return "BuilderTest{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", city='" + city + '\'' +
", age=" + age +
'}';
}
}
public class Builderdemo {
public static void main(String[] args) {
BuilderTest builder = new BuilderTest.Builder().setAge(18).setName("Lili").setCity("北京").builder();
System.out.println(builder);
}
}
比如:StringBuilder就是使用这种设计模式来实现
StringBuilder sb = new StringBuilder();
sb.append("hello").append("\t").append("world").append("!");
System.out.println(sb.toString());
迭代器模式(Iterator)
用于顺序访问集合对象的元素,不需要知道集合对象的底层表示;
- 意图:提供一种方法顺序访问一个聚合对象中各个元素,而又无需暴露该对象的内部表示。
- 优点:支持以不同的方式遍历一个聚合对象;迭代器简化了聚合类;在同一个聚合上可以有多个遍历‘在迭代器中增加新的聚合对象和迭代器类都很方便,无须修改原有代码。
’- 缺点:由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
创建接口
package com.westos.Demo1;
public interface Iterator {
public boolean hasNext();
public Object next();
}
public interface Containter {
public Iterator getIterator();
}
创建实现Container接口的实体类,该类实现了Iterator接口的内部类NameIterator
public class NameRepository implements Containter{
public String names[]={"Robert","John","Julie","Lora"};
@Override
public Iterator getIterator() {
return new NameIterator();
}
private class NameIterator implements Iterator{
int index;
@Override
public boolean hasNext() {
if(index<names.length){
return true;
}
return false;
}
@Override
public Object next() {
if(this.hasNext()){
return names[index++];
}
return null;
}
}
}
获取迭代器,并打印名字
public class IteratorPatternDemo {
public static void main(String[] args) {
NameRepository nr = new NameRepository();
for (Iterator iter=nr.getIterator();iter.hasNext();){
String name =(String) iter.next();
System.out.println("Name:"+name);
}
}
}
策略模式(Strategy)
在策略模式中,一个类的行为或其他算法可以在运行时更改,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的context对象。策略对象改变context对象的执行算法。
- 意图:定义一系列的算法,把它们一个个封装起来,并且使他们可互相替换;
- 主要解决:在有多种算法相似的情况下,使用if…else所带来的复杂和难以维护;
- 优点:算法可以自由切换;避免使用多重条件判断;扩展性好;
- 缺点:策略类会增多;所有策略类都需要对外暴露;
先来看不使用策略模式的算法,可以看到实现需求的方法只有在处理数据上有所不同,所以考虑把处理数据方式抽象成方法,这个方法就叫策略;
package com.westos.Demo2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class StrategyTest {
public static void main(String[] args) {
List<Integer> array = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
//给数组中的元素加3
//给数组中的元素减3
//给数组的元素求平方
//不使用策略模式
System.out.println(execAdd(array));
System.out.println(execSubtract(array));
System.out.println(execSquare(array));
}
private static ArrayList execAdd(List<Integer> array) {
ArrayList<Object> arrayLater = new ArrayList<>();
for (Integer integer : array) {
arrayLater.add(integer+3);
}
return arrayLater;
}
private static ArrayList execSubtract(List<Integer> array) {
ArrayList<Object> arrayLater = new ArrayList<>();
for (Integer integer : array) {
arrayLater.add(integer-3);
}
return arrayLater;
}
private static ArrayList execSquare(List<Integer> array) {
ArrayList<Object> arrayLater = new ArrayList<>();
for (Integer integer : array) {
arrayLater.add(integer*integer);
}
return arrayLater;
}
}
使用策略模式
package com.westos.Demo2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
public class StrategyTest {
public static void main(String[] args) {
List<Integer> array = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
//给数组中的元素加3
//给数组中的元素减3
//给数组的元素求平方
//不使用策略模式
//加三
System.out.println(exec(array, new Function() {
@Override
public Object apply(Object o) {
return (Integer)o+3;
}
}));
//减三
System.out.println(exec(array, new Function() {
@Override
public Object apply(Object o) {
return (Integer)o-3;
}
}));
//求平方
System.out.println(exec(array, new Function() {
@Override
public Object apply(Object o) {
return Math.pow((Integer)o,2);
}
}));
}
//给这个方法传入一个函数接口,
private static ArrayList exec(List<Integer> array, Function function) {
ArrayList<Object> arrayLater = new ArrayList<>();
for (Integer integer : array) {
//将处理数据的方式抽象成方法
arrayLater.add(function.apply(integer));
}
return arrayLater;
}
}
工厂模式(Factory)
工厂模式是Java中最常用的设计模式之一,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同接口来指向新创建的对象。
- 意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工场模式使其过程延迟到子类进行。
- 主要解决:主要解决接口选择问题;
- 如何解决:让其子类实现工场接口,返回的也是一个抽象的产品;
- 优点:一个调用者想创建对象只要知道其名称就可以了;扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以了;屏蔽产品的具体实现,调用者只关心产品的接口;
- 缺点:在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
创建一个接口
public interface Shape {
void draw();
}
创建接口实现类
public class Rectangle implements Shape{
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
public class Circle implements Shape{
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
public class Square implements Shape{
@Override
public void draw() {
System.out.println("Inside Squre::draw() method.");
}
}
创建一个工厂,生成基于给定信息的实体类的对象
public class ShapeFactory {
//使用getShape方法获取形状类型的对象
public Shape getShape(String shapeType){
if(shapeType==null){
return null;
//equalsIgnoreCase忽略大小写
}else if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
}else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
}else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
测试
public static void main(String[] args) {
ShapeFactory sf = new ShapeFactory();
//通过对象名获取对象
Shape cc = sf.getShape("CIRCLE");
cc.draw();
Shape re = sf.getShape("RECTANGLE");
re.draw();
Shape sq = sf.getShape("SQUARE");
sq.draw();
}
}
对工厂模式的理解
你现在要买一辆车,车就相当于上面的接口是一个抽象的概念,而车的牌子就相当于接接口的实现类,车场相当于造车的工厂,你去车场给别人说车牌名,给人就会给你这个牌子的车,你不需要关心这个车是怎么造出来的。
抽象工厂模式(Abstract Factory)
抽象工厂模式是围绕一个超级工厂创建的其他工厂。该超级工厂又称为其他工厂的工厂。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类,每个生成的工厂都能按照工厂模式提供对象。
- 意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们的具体的类。
- 何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品;
- 如何解决:在一个产品族里面,定义多个产品。
- 优点:当一个产品族中的多个对象被设计一起工作时,它能保证客户端始终只使用同一产品族中的对象,
- 缺点:产品族扩展很困难。
对抽象工厂模式的理解
和工厂模式原理一样,工厂模式是通过产品名字获取产品对象,抽象工厂模式是可以通过工厂的名字来获得工厂对象,然后给这个工厂对象传入产品名字获得产品对象;
创建shape接口和Color接口即工厂类接口
public interface Shape {
void draw();
}
public interface Color {
void fill();
}
创建实现接口的实体类即具体产品
public class Circle implements Shape{
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
public class Rectangle implements Shape{
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
public class Square implements Shape{
@Override
public void draw() {
System.out.println("Inside Squre::draw() method.");
}
}
public class Red implements Color{
@Override
public void fill() {
System.out.println("Inside Red::full() method");
}
}
public class Green implements Color{
@Override
public void fill() {
System.out.println("Inside Green::full() method");
}
}
public class Blue implements Color{
@Override
public void fill() {
System.out.println("Inside Blue::full() method");
}
}
实现工厂类,从中获取产品对象
public class ShapeFactory extends AbstractFactory{
@Override
public Color getColorFactory(String Color) {
return null;
}
//使用getShape方法获取形状类型的对象
@Override
public Shape getShapeFactory(String shapeType){
if(shapeType==null){
return null;
//equalsIgnoreCase忽略大小写
}else if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
}else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
}else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
public class ColorFactory extends AbstractFactory{
@Override
public Color getColorFactory(String colorType){
if(colorType==null){
return null;
}else if(colorType.equalsIgnoreCase("Red")){
return new Red();
}else if(colorType.equalsIgnoreCase("Green")){
return new Green();
}else if(colorType.equalsIgnoreCase("Blue")){
return new Blue();
}
return null;
}
@Override
public Shape getShapeFactory(String Shape) {
return null;
}
}
创建获取工厂的抽象工厂类
public abstract class AbstractFactory {
public abstract Color getColorFactory(String Color);
public abstract Shape getShapeFactory(String Shape);
}
实现抽象工厂类,从中获取工厂对象
public class FactoryProduct {
public static AbstractFactory getFactory(String FactoryName){
if(FactoryName==null){
return null;
}else if(FactoryName.equalsIgnoreCase("Shape")){
return new ShapeFactory();
}else if(FactoryName.equalsIgnoreCase("Color")){
return new ColorFactory();
}
return null;
}
}
简单工厂模式
有一个专门生产某个产品的类,鼠标工厂,给参数0生产戴尔鼠标,给参数1生产惠普鼠标;
工厂模式
是这个鼠标工厂的父类,有生产鼠标这个接口,戴尔工厂继承它就生产戴尔鼠标;惠普工厂继承它就生产惠普鼠标。
抽象工厂模式
抽象工厂模式可以生产鼠标即鼠标工厂也可以生产键盘即键盘工厂,戴尔继承它就可以生产戴尔鼠标+戴尔键盘,惠普继承它就可以生产惠普鼠标和惠普键盘;
过滤器模式(Filter/Criteria)
过滤器模式是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以及解耦的方式把它们连接起来,这种类型的设计模式属于结构模式,它结合多个标准来获得单一标准。
过滤器模式的实现在java8里面的典型应用就是分组操作,可以根据指定指标进行分组筛选。
创建人物类,属性名字,性别,婚姻状态。
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;
}
}
创建接口
public interface Criteria {
public List<Person> meetCriteria(List<Person> persons);
}
创建接口的实现类
public class CriteriaMale implements Criteria{
@Override
public List<Person> meetCriteria(List<Person> persons) {
ArrayList<Person> people = new ArrayList<>();
//如果性别为MALE就添加到新数组并返回
for (Person person : persons) {
if(person.getGender().equalsIgnoreCase("MALE")){
people.add(person);
}
}
return people;
}
}
public class CriteriaFemale implements Criteria{
@Override
public List<Person> meetCriteria(List<Person> persons) {
ArrayList<Person> people = new ArrayList<>();
//如果性别为FEMALE就添加到新数组并返回
for (Person person : persons) {
if(person.getGender().equalsIgnoreCase("FEMALE")){
people.add(person);
}
}
return people;
}
}
public class CriteriaSingle implements Criteria{
@Override
public List<Person> meetCriteria(List<Person> persons) {
ArrayList<Person> people = new ArrayList<>();
//如果性别为MALE就添加到新数组并返回
for (Person person : persons) {
if(person.getMaritalStatus().equalsIgnoreCase("SINGLE")){
people.add(person);
}
}
return people;
}
}
import java.util.List;
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> persons) {
List<Person> first = criteria.meetCriteria(persons);
return othercriteria.meetCriteria(first);
}
}
import java.util.List;
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> meetCriteria(List<Person> persons) {
List<Person> first = criteria.meetCriteria(persons);
List<Person> secend = othercriteria.meetCriteria(persons);
for (Person person : first) {
if(!secend.contains(person)){
secend.add(person);
}
}
return secend;
}
}
测试类
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Person> peopleArray = Arrays.asList(
new Person("孙悟空", "MALE", "Single"),
new Person("唐僧", "MALE", "Single"),
new Person("王母娘娘", "FEMALE", "NoSingle"),
new Person("嫦娥", "FEMALE", "Single"),
new Person("如来", "MALE", "Single"));
CriteriaMale criteriaMale = new CriteriaMale();
CriteriaFemale criteriaFemale = new CriteriaFemale();
CriteriaSingle criteriaSingle = new CriteriaSingle();
//按MALE分组
List<Person> male = criteriaMale.meetCriteria(peopleArray);
//按FEMALE分组
List<Person> female = criteriaFemale.meetCriteria(peopleArray);
//按SINGLE分组
List<Person> single = criteriaSingle.meetCriteria(peopleArray);
//满足single并且为male
AndCriteria andCriteria = new AndCriteria(criteriaMale, criteriaSingle);
//满足single或female
OrCriteria orCriteria = new OrCriteria(criteriaFemale, criteriaSingle);
printArray(male);
printArray(female);
printArray(single);
printArray(andCriteria.meetCriteria(peopleArray));
printArray(orCriteria.meetCriteria(peopleArray));
}
public static void printArray(List<Person> persons){
for (Person person : persons) {
System.out.print(
person.getName()+":{"
+person.getGender()+","
+person.getMaritalStatus()+"}"
);
}
System.out.println();
}
}