建造者模式
定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
个人理解
和工厂模式有些相似,都是用来创建一个对象,并且用户不需要去关心实际的创建过程,区别在于建造者模式着重于对部件的组装来完成对象的创建,一步步的去创建对象。例如一个汽车对象,工厂模式可能就是返回汽车对象,无需关系各部分是如何创建出来的。而建造者模式则还关心这个汽车的轮胎部分 ,座椅部分....并且工厂模式返回不同的汽车对象是通过接口继承,而建造者模式则是通过组成部分不同来创建不同的对象。建造者模式粒度更加细。并且建造者模式产生的产品之间差异性不能很大,例如汽车产品一定是由这三个部分构成,只是在这个三个部分使用的东西不一样。具体看例子。
例子
首先创建一个汽车类 (具体产品)
public class CarProduct {
//轮胎
private String tire;
//座椅
private String chairs;
省略get set和toString
}
创建一个建造汽车的抽象建造类
public abstract class Builder {
//需要构架的产品
protected CarProduct carProduct = new CarProduct();
//创建轮胎的抽象方法
public abstract void buildTire();
//创建座椅的抽象方法
public abstract void buildChairs();
//返回建造的产品
public CarProduct getCarProduct(){
return carProduct;
}
}
我们要创建某种轮胎和某种桌椅的汽车对象只需要继承这个抽象类实现方法即可。例如现在需要创建一个使用了米其林轮胎和奥迪桌椅的汽车和一个使用了朝阳轮胎和长安桌椅的汽车,我们只需要实现上面这个抽象类根据组成部分的不同去返回不同的汽车对象。
public class ProductBuilderA extends Builder {
@Override
public void buildTire() {
carProduct.setTire("使用米其林轮胎");
}
@Override
public void buildChairs() {
carProduct.setChairs("使用奥迪桌椅");
}
}
public class ProductBuilderB extends Builder {
@Override
public void buildTire() {
carProduct.setTire("使用朝阳轮胎");
}
@Override
public void buildChairs() {
carProduct.setChairs("使用长安桌椅");
}
}
但是现在还有一个问题,客户端创建这个对象还是需要去知道设置轮胎,设置设置桌椅这样方法,所以现在还需要建造者模式中一个非常重要的类,,指挥者(Director)。这个类用来隔离用户与建造过程的关联。
public class Director {
private Builder builder;
public Director(Builder builder){
this.builder = builder;
}
//返回具体产品的方法
public CarProduct createCar(){
builder.buildTire();
builder.buildChairs();
return builder.getCarProduct();
}
}
我们需要返回某种需求的对象,只需要面对这个Director类即可。
客户端代码:
public static void main(String[] args) {
//利用指挥官对象来创建A类汽车
CarProduct carProductA = new Director(new ProductBuilderA()).createCar();
//利用指挥官对象来创建B类汽车
CarProduct carProductB = new Director(new ProductBuilderB()).createCar();
System.out.println(carProductA);
System.out.println(carProductB);
}
运行结果:
![6708c7fd3d4889d17cfd8b7f4a919ecb.png](https://i-blog.csdnimg.cn/blog_migrate/8c43259f1103650b4f1e59a7eed61432.png)
上面这个例子就是使用的建造者模式创建汽车对象,更加注重汽车的组成部分。
建造者模式UML结构图和当前例子UML对比
![012536ba1e7068c48b8da8f1b0fdd763.png](https://i-blog.csdnimg.cn/blog_migrate/3c3762fa58af0ccf173e7d461ddc2989.jpeg)
![382f4f8721d912bd4bb28ad2bf0d59cb.png](https://i-blog.csdnimg.cn/blog_migrate/d3a69e62073d16d3d412be963686b3d9.jpeg)
由此可见,建造者模式不建造构架差异性很大的产品
参考资料:
《大话设计模式》
【设计模式】 模式PK:工厂模式VS建造者模式www.cnblogs.com![f20331a9eca4f72e661bcdea9fae9074.png](https://i-blog.csdnimg.cn/blog_migrate/93139cef34a1e20c80669ec7a1586d74.png)
![a349034123e693c02bbdd9bdeab14a82.png](https://i-blog.csdnimg.cn/blog_migrate/bf11fde9b7bdb991db81720f1258b0f0.jpeg)
![966ff448840a1736f2c0de5dafa251b0.png](https://i-blog.csdnimg.cn/blog_migrate/2864fb1a4d48421e1f1758c6c5eb58b8.png)
观察者模式
定义
观察 者模式定义了一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
个人理解
就是将一些观察者对象绑定到一个主题对象中去,只要主题对象发生变化就通知绑定了这个主题对象的所有观察者对象。有点像我们高中上自习的时候会找一个人来帮我们看风,只要他看到老师来教室了,就通知我们老师来了,然后我们提前停止吵闹,开始学习。这个看风的人就是主题对象,我们就是观察者对象。
例子
就使用上面这个上自习看风的例子。我们就是观察者,而作为观察者的我们可能上自习在看NBA,也可能在聊天,所以我们使用一个抽象类来表示观察者。通知我们的人可能是学生,也可能是一位友好的老师,为了使代码符合开放封原则,所以我们也定义一个通知者(主题对象)抽象类。
//观察者抽象类
public abstract class ObServer {
protected String name;
protected Subject subject;
//Subject 是通知者
public ObServer(String name,Subject subject){
this.name = name;
this.subject = subject;
}
//观察者被通知调用的方法
public abstract void Update();
}
//通知者抽象类
public abstract class Subject {
//观察者列表
private List<Observer> observers = new ArrayList<>();
//添加观察者的方法
void attach(Observer observer){
observers.add(observer);
}
//移除观察者的方法
void detack(Observer observer){
observers.remove(observer);
}
//通知方法
void myNotify(){
//遍历观察者列表 都调用它的update方法
for(Observer observer:observers){
observer.Update();
}
}
}
//看nba的同学
public class NBAObserver extends Observer {
public NBAObserver(String name, Subject subject) {
super(name, subject);
}
@Override
public void Update() {
System.out.println(this.name+"关闭nba,继续学习");
}
}
//聊天的同学
public class ChatObserver extends Observer {
public ChatObserver(String name, Subject subject) {
super(name, subject);
}
@Override
public void Update() {
System.out.println(this.name+"停止聊天,继续学习");
}
}
//放风的学生
public class Student extends Subject {
@Override
public void myNotify() {
System.out.println("我是学生,老师来了..");
super.myNotify();
}
}
//友好的放风老师
public class Teacher extends Subject {
@Override
void myNotify() {
System.out.println("我是友好的老师,你们老师来了");
super.myNotify();
}
}
//客户端代码
public static void main(String[] args) {
//学生当通知者为我们防风
Subject subject = new Student();
//创建看nba和聊天的同学 并且绑定到通知者上去 我这里这个例子传进通知者并没有使用到它 可以不传 但是实际情况很可能要用到
Observer nbaObserver = new NBAObserver("小明",subject);
Observer chatObserver = new ChatObserver("小军",subject);
//观察者绑定要通知者上去
subject.attach(nbaObserver);
subject.attach(chatObserver);
//学生通知者发出通知告诉我们老师来了
subject.myNotify();
//友好的老师当通知者为我们放风
subject = new Teacher();
//将看nba和聊天的同学绑定到这个新的通知者上去
subject.attach(nbaObserver);
subject.attach(chatObserver);
//友好的老师告诉我们老师来了
subject.myNotify();
}
运行结果:
![8b5edc7f75d3a46610142bfa6022eca1.png](https://i-blog.csdnimg.cn/blog_migrate/c49253aa02ad7082924bc63b7524e695.jpeg)
上面这个例子就是一个观察者模式
观察者模式UML结构和例子UML图对应关系
![6fa64004957deadb7bd4ee8b8bc3d0fa.png](https://i-blog.csdnimg.cn/blog_migrate/12fe7c44daa7aec94d3b0a34feb48115.jpeg)
例子:
![88e5fa68a58ff61394ccfe71ec2ed43b.png](https://i-blog.csdnimg.cn/blog_migrate/e2f113c06291f8ac48b67393b9ae834a.jpeg)
总结
观察者模式还有一些不足,比如所有观察者都要去实现Observer接口,并且所有观察者更新方法都为update,可以通过事件委托机制解决上面的问题,但是java好像没有事件委托机制....所以这个自己查资料吧
抽象工厂模式
定义
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
个人理解
其实就是工厂方法模式的增强,之前的工厂方法模式一个工厂只创建了一种商品,如果一个工厂可以创建一系列商品,那么这个模式就是抽象工厂模式。例如之前的例子https://www.zhihu.com/people/bai-tuo-i/posts,自行车和汽车工厂都只能生产自行车和汽车。我现在新增一个配件接口,下面有两个实现类自行车配件和汽车配件,然后在自行车工厂和汽车工厂分别新增一个创建自行车配件对象和创建汽车配件的方法,那么现在自行车工厂既能生产自行车也能生成自行车配件,汽车工厂类似,这样就实现了生成一系列产品,这就是抽象工厂模式。
例子
就按上面的例子来
//配件接口
public interface Accessories {
void printName();
}
//自行车配件
public class BicycleAccessories implements Accessories {
@Override
public void printName() {
System.out.println("自行车配件");
}
}
//汽车配件
public class BusAccessories implements Accessories {
@Override
public void printName() {
System.out.println("汽车配件");
}
}
//修改后的工厂 工厂接口的修改省略..
//汽车工厂
public class BusFactory implements VehicleFactory2 {
@Override
public Vehicle getVehicle() {
return new Bus();
}
//创建汽车配件对象
@Override
public Accessories getAccessories() {
return new BusAccessories();
}
}
//自行车工厂
public class BicycleFactory implements VehicleFactory2 {
@Override
public Vehicle getVehicle() {
return new Bicycle();
}
//创建自行车配件
@Override
public Accessories getAccessories() {
return new BicycleAccessories();
}
}
工厂经过上面的修改后就能够返回一系列的产品了。
抽象工厂模式的UML图(这个真的画不下去了.....)
![164383beda3fbb2f7099d02d3248df8f.png](https://i-blog.csdnimg.cn/blog_migrate/5fd9d348d66253205c0c383a915a2f04.jpeg)
上面例子修改为抽象工厂模式对应的UML图
![80fdf49eeb4085dc3246269acc24ae94.png](https://i-blog.csdnimg.cn/blog_migrate/dd3175d7c3839008e2814cd0e94816d8.jpeg)
其实抽象模式还有很大的缺点,例如现在上面我们如果去再添加一个贴牌产品,那么需要添加三个类,并且需要去修改三个工厂。这样使非常麻烦的。并且如果我们需要修改工厂,如果有多个地方new 的工厂,那么需要在多个地方去更改这个new的代码, 这样真的是太糟糕了。所以有一种新的方案,利用简单工厂模式来改进抽象工厂模式,不过又会出现switch的语句选择,消除switch语句又可以通过反射进行解决,可以看这篇博客最后那点。但是不管怎样,你新添加一个系列中的一个商品,类的增加都是避免不的。
简单工厂模式、工厂模式以及抽象工厂模式(具体) - cosmos_lee - CSDN博客blog.csdn.net![8447009bda2f0a7a16d481618c33e2dd.png](https://i-blog.csdnimg.cn/blog_migrate/62fb3ea102ad4158401a25f8c3761747.png)
总结
所有用在简单工厂的地方,都可以考虑用反射技术来去除switch或if,解除判断分支带来的耦合。