设计模式七大原则、类之间关系https://blog.csdn.net/qq_42432141/article/details/107960977
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下:
什么是单例模式?
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例, 并且该类只提供一个取得其对象实例的方法(静态方法)。
饿汉式特点
一加载类,就实例化对象
// 饿汉式 1
class EagerSingleton {
// 1、构造器私有化,外部只能new
private EagerSingleton() {
}
// 2、本类内部创建对象实例
private final static EagerSingleton INSTANCE = new EagerSingleton();
// 3、对外提供一个共有的静态方法,返回实例对象
public static EagerSingleton getInstance() {
return INSTANCE;
}
}
// 饿汉式 2
class EagerSingleton {
// 构造器私有化,外部只能new
private EagerSingleton() {
}
// 2、本类内部创建对象实例
private static EagerSingleton instance;
static { // 在静态代码块中,创建单例对象
instance = new EagerSingleton();
}
// 3、对外提供一个共有的静态方法,返回实例对象
public static EagerSingleton getInstance() {
return instance;
}
}
优缺点
懒汉式特点
什么时候使用,什么时候加载
/**
* 懒汉式 1
* 线程不安全
* 在多线程下,多个进程同时进入 if (instance == null)判断语句块的时候
* 就会创建多个实例
*/
class LazySingleton {
private static LazySingleton instance;
public LazySingleton() {
}
/**
* 提供一个静态的共有方法,当使用到该方法的时候,采取创建instance
* @return 返回创建的instance
*/
public static LazySingleton getInstance(){
if (instance == null){
instance = new LazySingleton();
}
return instance;
}
}
优缺点:
/**
* 懒汉式 2
* 线程安全 同步方法
*/
class LazySingleton {
private static LazySingleton instance;
public LazySingleton() {
}
/**
* 提供一个静态的共有方法,加入同步处理的代码,解决线程安全问题
* @return 返回创建的instance
*/
public static synchronized LazySingleton getInstance(){
if (instance == null){
instance = new LazySingleton();
}
return instance;
}
}
优缺点
多个线程还是会进入if判断中,进行等待,实例化好对象后,下一个线程依旧会实例。
public static LazySingleton getInstance(){
if (instance == null){
synchronized(LazySingleton.class){
instance = new LazySingleton()
}
}
return instance;
}
class LazySingleton {
private static volatile LazySingleton instance;
public LazySingleton() {
}
/**
* 提供一个静态的共有方法,加入双重检查代码,解决线程安全问题,同时解决懒加载问题,又解决了效率问题
* @return 返回创建的instance
*/
public static synchronized LazySingleton getInstance() {
// 第一次判断
if (instance == null) {
synchronized (LazySingleton.class) {
// 第二次判断
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
/**
* 静态内部类
*/
class StaticSingleton {
/**
* 构造器私有化
*/
private StaticSingleton() {
}
/**
* 写一个静态内部类, 该类中有一个静态属性 StaticSingleton
*/
private static class StaticSingletonInstance{
private static final StaticSingleton INSTANCE = new StaticSingleton();
};
/**
* 提供一个静态的共有方法,直接返回 StaticSingletonInstance.INSTANCE
* @return 返回创建的instance
*/
public static synchronized StaticSingleton getInstance() {
return StaticSingletonInstance.INSTANCE;
}
}
优缺点:
public class SingletonTest07 {
public static void main(String[] args) {
EnumSingleton instance = EnumSingleton.INSTANCE;
EnumSingleton instance2 = EnumSingleton.INSTANCE;
System.out.println(instance == instance2);
}
}
enum EnumSingleton {
// 属性
INSTANCE;
public void sayOk() {
System.out.println("ok~~");
}
}
优缺点
又名:静态工厂模式
简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式.
实例:订购pizza
// pizza 抽象类
public abstract class Pizza {
// pizza 名字
protected String name;
/** 抽象方法 prepare
* 准备原材料,不同的pizza 原材料不一样
*/
public abstract void prepare()
// 烘烤
public void bake() {
System.out.println(name + " baking ... ");
}
// 切割
public void cut() {
System.out.println(name + " cutting ... ");
}
// 打包
public void box() {
System.out.println(name + " boxing ... ");
}
public void setName(String name) {
this.name = name;
}
}
// 希腊pizza
public class GreekPizza extends Pizza{
@Override
public void prepare() {
System.out.println(" 给希腊pizza准备原材料 .... ");
}
}
// 奶酪pizza
public class CheesePizza extends Pizza{
@Override
public void prepare() {
System.out.println(" 给制作奶酪pizza 准备原材料 .... ");
}
}
// 制作pizza
public class OrderPizza {
/**
* 定义一个简单工厂对象
*/
SimpleFactory simpleFactory=null;
Pizza pizza = null;
public OrderPizza(SimpleFactory simpleFactory) {
setSimpleFactory(simpleFactory);
}
public void setSimpleFactory(SimpleFactory simpleFactory){
// 用户输入的种类
String orderType = "";
// 设置简单工厂对象
this.simpleFactory = simpleFactory;
do {
// 拿到用户想订购的类型
orderType = getType();
// 拿到制作好的pizza
pizza = this.simpleFactory.creatPizza(orderType);
if (pizza!=null){
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else {
System.out.println("订购pizza 失败 ... ");
break;
}
}while (true);
}
// 写一个方法,可以获取用户希望订购的pizza种类
private String getType() {
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("please input pizza type: ");
String str = bufferedReader.readLine();
return str;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
// 简单工厂
public class SimpleFactory {
/**
* 根据orderType 返回对应的Pizza对象
* @param orderType
* @return
*/
public Pizza creatPizza(String orderType) {
Pizza pizza = null;
String greek = "greek";
String cheese = "cheese";
System.out.println("使用简单的工厂模式");
if (greek.equals(orderType)) {
pizza = new GreekPizza();
pizza.setName("greek");
} else if (cheese.equals(orderType)) {
pizza = new GreekPizza();
pizza.setName("cheese");
}
return pizza;
}
}
public class PizzaStore {
public static void main(String[] args) {
// 使用简单工厂模式
new OrderPizza(new SimpleFactory());
System.out.println("退出程序 ... ");
}
}
问题来了! 新增pizza种类如何修改?
// 创建胡椒pizza 继承pizza类
public class PepperPizza extends Pizza{
@Override
public void prepare() {
System.out.println("给胡椒pizza准备原材料 ... ");
}
}
有新的需求,北京奶酪pizza,伦敦胡椒pizza,如何实现?
代码实现
// pizza 抽象类
public abstract class Pizza {
// pizza 名字
protected String name;
/** 抽象方法 prepare
* 准备原材料,不同的pizza 原材料不一样
*/
public abstract void prepare()
// 烘烤
public void bake() {
System.out.println(name + " baking ... ");
}
// 切割
public void cut() {
System.out.println(name + " cutting ... ");
}
// 打包
public void box() {
System.out.println(name + " boxing ... ");
}
public void setName(String name) {
this.name = name;
}
}
// 伦敦奶酪pizza
public class LDPepperPizza extends Pizza{
@Override
public void prepare() {
setName("伦敦胡椒pizza");
System.out.println("伦敦胡椒pizza 准备材料中");
}
}
// 伦敦奶酪pizza
public class LDCheesePizza extends Pizza {
@Override
public void prepare() {
setName("伦敦奶酪pizza");
System.out.println("伦敦奶酪pizza 准备材料中");
}
}
// 北京胡椒pizza
public class BJPepperPizza extends Pizza{
@Override
public void prepare() {
setName("北京胡椒pizza");
System.out.println("北京的胡椒pizza 准备材料 ... ");
}
}
// 北京奶酪pizza
public class BJCheesePizza extends Pizza{
@Override
public void prepare() {
setName("北京奶酪pizza");
System.out.println("北京的奶酪pizza 准备材料 ... ");
}
}
// 选择pizza
public abstract class OrderPizza {
/**
* 定义一个抽象方法 createPizza,让各个工厂子类自己实现
* @param orderType
* @return
*/
abstract Pizza createPizza(String orderType);
/**
* 构造器
*/
public OrderPizza() {
Pizza pizza = null;
// 订购Pizza的类型
String orderType = null;
do {
orderType = getType();
// 抽象方法 由工厂子类完成
pizza = createPizza(orderType);
// 输出pizza过程
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} while (true);
}
/**
* 写一个方法,可以获取用户希望订购的pizza种类
*/
private String getType() {
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("please input pizza type: ");
String str = bufferedReader.readLine();
return str;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
// 伦敦pizza选择
public class LDOrderPizza extends OrderPizza{
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
String pepper = "pepper";
String cheese = "cheese";
if (cheese.equals(orderType)){
pizza = new LDCheesePizza();
}else if(pepper.equals(orderType)){
pizza = new LDPepperPizza();
}
return pizza;
}
}
// 北京pizza选择
public class BJOrderPizza extends OrderPizza{
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
String pepper = "pepper";
String cheese = "cheese";
if (cheese.equals(orderType)){
pizza = new BJCheesePizza();
}else if(pepper.equals(orderType)){
pizza = new BJPepperPizza();
}
return pizza;
}
}
public class PizzaStore {
public static void main(String[] args) {
BJOrderPizza bjOrderPizza = new BJOrderPizza();
}
}
代码实现:
这几个类和上面的一样
public interface AbsFactory {
// 抽象方法: 让工厂子类来具体实现
public Pizza createPizza(String orderType);
}
public class BJFactory implements AbsFactory{
// 北京工厂 根据type实现制作pizza
@Override
public Pizza createPizza(String orderType) {
System.out.println("创建北京工厂 使用抽象模式");
Pizza pizza = null;
String cheese = "cheese";
String pepper = "pepper";
if (cheese.equals(orderType)){
pizza = new BJCheesePizza();
}else if (pepper.equals(orderType)){
pizza = new BJPepperPizza();
}
return pizza;
}
}
public class LDFactory implements AbsFactory{
// 伦敦工厂 根据type实现制作pizza
@Override
public Pizza createPizza(String orderType) {
System.out.println("创建伦敦工厂 使用抽象模式");
Pizza pizza = null;
String cheese = "cheese";
String pepper = "pepper";
if (cheese.equals(orderType)){
pizza = new LDCheesePizza();
}else if (pepper.equals(orderType)){
pizza = new LDPepperPizza();
}
return pizza;
}
}
public class OrderPizza {
AbsFactory factory;
// 构造器 实例化工厂的时候 设置工厂的种类
public OrderPizza(AbsFactory factory) {
setAbsFactory(factory);
}
// 实例化的时候 根据传入的工厂,去创建对应的pizza
// 具体pizza的type 参考getType()方法
private void setAbsFactory(AbsFactory factory) {
Pizza pizza = null;
String orderType = "";
this.factory = factory;
do {
orderType = getType();
// factory 可能是北京的工厂子类 也可能是伦敦的工厂子类
pizza = factory.createPizza(orderType);
if (pizza != null){
// 输出pizza过程
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else {
System.out.println("订购失败 ... ");
break;
}
} while (true);
}
// 写一个方法,可以获取用户希望订购的pizza种类
private String getType() {
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("please input pizza type: ");
String str = bufferedReader.readLine();
return str;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
public class PizzaStore {
public static void main(String[] args) {
new OrderPizza(new BJFactory());
}
}
子类特别多的话使用抽象工厂,子类很少的话使用工厂方法。
代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象
代理模式有不同的形式, 主要有三种 静态代理、动态代理(JDK 代理、接口代理)和 Cglib 代理 (可以在内存动态的创建对象,而不需要实现接口, 他是属于动态代理的范畴) 。
代理模式:
1、创建接口
2、创建被代理对象 实现接口
3、创建代理对象 实现接口,创建被代理对象的引用 在对应的方法中 调用被代理对象的方法 并进行扩展
4、实例化被代理对象 和 代理对象
5、代理对象和被代理对象关联
6、调用代理对象的方法
代理对象:
方法实现
首先先实现被代理对象的方法(创建引用)
对方法进行扩展
// 接口
public interface Person {
void show();
void eat(String food);
}
// 被代理类
public class Student implements Person {
String name;
String sclass; // 班级
@Override
public void show() {
System.out.println("我是" + sclass + "班的学生: " + name);
}
@Override
public void eat(String food) {
System.out.println("我是:" + name + "我爱吃" + food);
}
public Student(String name, String sclass) {
this.name = name;
this.sclass = sclass;
}
}
// 被代理类
public class StudentProxy implements Person{
// 定义一个成员变量 来记录被代理对象
Person person;
public StudentProxy(Person person) {
this.person = person;
}
@Override
public void show() {
person.show();
System.out.println("再来首歌");
}
@Override
public void eat(String food) {
person.eat(food);
System.out.println("注意: 粒粒皆辛苦");
}
}
public class TestProxy {
public static void main(String[] args) {
// 先有代理对象
Student student = new Student("jsu", "信息");
// 创建代理对象
// 代理对象和被代理对象关联
StudentProxy studentProxy = new StudentProxy(student);
// 使用代理对象即可
studentProxy.show();
studentProxy.eat("芒果");
}
}
缺点:
代理类和被代理类必须实现同一个接口 局限性比较大 而且代理类很多
代理类只能对指定接口类型的实现类进行控制 而且只能扩展接口中定义的方法
一旦接口增加方法,目标对象与代理对象都要维护
优点:
在不修改目标对象的功能前提下, 能通过代理对象对目标功能扩展
1 创建一个代理工厂类 实现接口InvocationHandler
2 定义成员变量记录 被代理对象
3 通过构造方法的参数列表 关联被代理对象
4 实现invoke方法 对目标对象的方法进行控制
5 定义一个方法:getInstance 来创建动态创建代理对象
6 定义被代理类:必须实现接口
7 创建被代理对象
8 创建代理工厂对象 并关联被代理对象
9 调用工厂对象的getProxyInstance方法来动态获取代理对象
// 接口
public interface IActive {
void show();
void work();
}
public class Worker implements IActive {
String name;
Integer age;
public Worker(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public void show(){
System.out.println("我是一名x学生:"+name+"今年"+age+"岁");
}
@Override
public void work(){
System.out.println(name+"学生,正在学习!");
}
}
// 动态代理工厂类
public class ProxyFactory implements InvocationHandler {
// 定义成员变量记录 被代理对象
private Object object;
// 通过构造方法的参数列表 关联被代理对象
public ProxyFactory(Object object) {
this.object = object;
}
// 实现invoke方法 对目标对象的方法进行控制 代理对象的方法每次调用的时候 就会执行invoke
/*
Object invoke(Object proxy, Method method, Object[] args)
proxy : 代理对象
method : 被代理对象的方法
args : 方法的实参
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("目标对象方法之前的 ---- 预处理的代码");
// 调用目标对象的方法
Object invoke = method.invoke(object, args);
System.out.println("目标对象方法之后的 ---- 预处理的代码");
return invoke;
}
// 定义一个方法: getProxyInstance
// 此方法的目的 就是动态生成代理对象
public Object getProxyInstance() {
/*
Proxy.newProxyInstance(loader, interfaces, h);
loader : 代理对象的类加载器
interfaces : 代理对象要实现的接口 -- 被代理对象实现的接口
h : InvocationHandler的实现对象
*/
Object proxy = Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(),
this);
return proxy;
}
}
// 测试类
public static void main(String[] args) {
// 创建被代理对象
Worker su = new Worker("su", 28);
// 创建工厂对象
ProxyFactory proxyFactory = new ProxyFactory(su);
// 调用工厂对象的getProxyInstance方法
IActive proxyInstance = (IActive) proxyFactory.getProxyInstance();
proxyInstance.show();
proxyInstance.work();
}
优势
CGLIB相比于JDK动态代理更加强大,JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有接口,那么Java动态代理就没法使用了
导包
<groupId>cglibgroupId>
<artifactId>cglibartifactId>
<version>2.2.2version>
代码实现
public class ProxyFactory implements MethodInterceptor {
// 维护一个目标对象
private Object target;
// 构造器 传入一个被代理的对象
public ProxyFactory(Object target) {
this.target = target;
}
// 重写 intercept 方法,会调用目标对象的方法
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib 代理模式 开始");
Object invoke = method.invoke(target, objects);
System.out.println("Cglib 代理模式 结束");
return invoke;
}
//返回一个代理对象: 是target 对象的代理对象
public Object getProxyInstance() {
//1. 创建一个工具类
Enhancer enhancer = new Enhancer();
//2. 设置父类
enhancer.setSuperclass(target.getClass());
//3. 设置回调函数
enhancer.setCallback(this);
//4. 创建子类对象,即代理对象
return enhancer.create();
}
}
public class Teacher {
public String teach() {
System.out.println(" 老师授课中 , 我是 cglib 代理,不需要实现接口 ");
return "hello";
}
}
// 测试
public class CglibTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建目标对象
Teacher target = new Teacher();
//获取到代理对象,并且将目标对象传递给代理对象
Teacher proxyInstance = (Teacher) new ProxyFactory(target).getProxyInstance();
//执行代理对象的方法,触发 intercept 方法,从而实现 对目标对象的调用
String res = proxyInstance.teach();
System.out.println("res=" + res);
}
}
实例:克隆羊
public class Sheep {
private String name;
private Integer age;
private String color;
public Sheep(String name, Integer age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
// 自己生成get set toString方法
}
public class Client {
public static void main(String[] args) {
// 传统的方法
Sheep sheep = new Sheep("tom", 1, "白色");
// 克隆羊
Sheep sheep1 = new Sheep(sheep.getName(), sheep.getAge(),sheep.getColor());
Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(),sheep.getColor());
Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(),sheep.getColor());
Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(),sheep.getColor());
System.out.println(sheep);
System.out.println(sheep1);
System.out.println(sheep2);
System.out.println(sheep3);
System.out.println(sheep4);
}
}
对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。
对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值
前面我们克隆羊就是浅拷贝
浅拷贝是使用默认的 clone()方法来实现
sheep = (Sheep) super.clone();
public class Sheep implements Cloneable{
private String name;
private Integer age;
private String color;
// 克隆该实例 使用默认的clone方法完成
@Override
protected Object clone() {
Sheep sheep = null;
try{
sheep = (Sheep)super.clone();
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
return sheep;
}
}
public class Client {
public static void main(String[] args) {
// 传统的方法
Sheep sheep = new Sheep("tom", 1, "白色");
// 克隆羊
Sheep clone1 = (Sheep) sheep.clone();
Sheep clone2 = (Sheep) sheep.clone()
}
}
public class DeepCloneableTarget implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private String cloneName;
private String cloneClass;
// 构造器
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
// 因为该类的属性,都是 String , 因此我们这里使用默认的 clone 完成即可
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class DeepProtoType implements Serializable, Cloneable {
public String name;
// 引用类型
public DeepCloneableTarget deepCloneableTarget;
public DeepProtoType() {
super();
}
// 深拷贝 - 方式 1 使用 clone 方法
@Override
protected Object clone() throws CloneNotSupportedException {
Object deep = null;
//这里完成对基本数据类型(属性)和 String 的克隆
deep = super.clone();
//对引用类型的属性,进行单独处理
DeepProtoType deepProtoType = (DeepProtoType) deep;
deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
return deepProtoType;
}
// 深拷贝 - 方式 2 通过对象的序列化实现 (推荐)
public Object deepClone() {
//创建流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
//当前这个对象以对象流的方式输出
oos.writeObject(this);
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
DeepProtoType copyObj = (DeepProtoType) ois.readObject();
return copyObj;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
System.out.println(e2.getMessage());
}
}
}
}
public class Client {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
DeepProtoType p = new DeepProtoType(); p.name = "宋江";
p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");
//方式 1 完成深拷贝
// DeepProtoType p2 = (DeepProtoType) p.clone();
//
// System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
// System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());
//方式 2 完成深拷贝
DeepProtoType p2 = (DeepProtoType) p.deepClone();
System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());
}
}
未使用建造者模式
// Product 产品角色
public class House {
private String basic;
private String wall;
private String roofed;
// 生成getter setter
}
// 抽象建造者
public abstract class AbstractHouseBuilder {
protected House house = new House();
// 打地基
public abstract void buildBasic();
// 砌墙
public abstract void buildWalls();
//封顶
public abstract void roofed();
// 建造房子
//房子建造好, 将产品(房子)返回
public House buildHouse(){
return house;
}
}
//具体建造者
public class CommonHouse extends AbstractHouseBuilder {
@Override
public void buildBasic() {
System.out.println(" 普通房子打地基5米 ... ");
}
@Override
public void buildWalls() {
System.out.println(" 普通房子砌墙10cm ... ");
}
@Override
public void roofed() {
System.out.println(" 普通房子封顶茅草 ... ");
}
}
public class HighHouse extends AbstractHouseBuilder{
@Override
public void buildBasic() {
System.out.println(" 高楼房子打地基100米 ... ");
}
@Override
public void buildWalls() {
System.out.println(" 高楼房子砌墙20cm ... ");
}
@Override
public void roofed() {
System.out.println(" 高楼房子封顶玻璃顶 ... ");
}
}
// 指挥者 动态指定制作流程 返回产品
public class HouseDirector {
AbstractHouseBuilder houseBuilder = null;
// 构造器传入houseBuilder
public HouseDirector(AbstractHouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
// 通过setter 传入houseBuilder
public void setHouseBuilder(AbstractHouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
// 如何处理建造房子的流程,交给指挥者
public House constructHouse(){
houseBuilder.buildBasic();
houseBuilder.buildWalls();
houseBuilder.roofed();
return houseBuilder.buildHouse();
}
}
// 测试
public class Client {
public static void main(String[] args) {
// 建造模式的 普通房子和高楼 并不是属性上的不同 而是建造的过程流程不同
// 盖普通房子
CommonHouse commonBuilder = new CommonHouse();
// 准备盖房子的指挥者
HouseDirector houseDirector = new HouseDirector(commonBuilder);
// 完成盖房子 返回房子
House house = houseDirector.constructHouse();
}
}'
客户端(使用程序)不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象
每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象
可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰, 也更方便使用程序来控制创建过程
增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”
建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,因此在这种情况下,要考虑是否选择建造者模式.
抽象工厂模式 VS 建造者模式
抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产即可。而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品
以生活中充电器的例子来讲解适配器,充电器本身相当于 Adapter,220V 交流电相当于 src (即被适配者),我们的目 dst(即 目标)是 5V 直流电
// 被适配的类
public class Voltage220V {
public int output220V(){
int src = 220;
System.out.println("电压为: "+ src +"V");
return src;
}
}
// 适配接口
public interface IVoltage5V {
// 转换为5v
public int output5V();
}
// 适配器类
public class VoltageAdapter extends Voltage220V implements IVoltage5V {
@Override
public int output5V() {
// 获取到220v的电压
int src = output220V();
// 获取到需要的电压 220/44=5V
int dstV = src / 44;
return dstV;
}
}
// 目标
public class Phone {
// 充电
public void charging(IVoltage5V iVoltage5V){
if (iVoltage5V.output5V() == 5){
System.out.println("电压为5V, 开始充电");
}else {
System.out.println("电压不是5V,无法充电");
}
}
}
// 测试
public class Client {
public static void main(String[] args) {
System.out.println("类适配器模式");
Phone phone = new Phone();
phone.charging(new VoltageAdapter());
}
}
以生活中充电器的例子来讲解适配器,充电器本身相当于 Adapter,220V 交流电相当于 src (即被适配者),我们的目 dst(即目标)是 5V 直流电,使用对象适配器模式完成。
// 与类适配器比较只有VoltageAdapter 不同
public class VoltageAdapter implements IVoltage5V {
// 关联关系中的- 聚合关系
private Voltage220V voltage220V;
//通过构造器,传入一个Voltage220V实例
public VoltageAdapter(Voltage220V voltage220V) {
this.voltage220V = voltage220V;
}
@Override
public int output5V() {
// 定义需要的电压 默认为0
int dstV = 0;
// 判断voltage220V对象是否存在
if (null != voltage220V) {
// 获取到220v的电压
int src = voltage220V.output220V();
System.out.println("使用对象适配器进行转换");
dstV = src / 44;
System.out.println("适配完成,输出的电压为=" + dstV);
}
return dstV;
}
}
public class Client {
public static void main(String[] args) {
System.out.println("对象适配器模式");
Phone phone = new Phone();
phone.charging(new VoltageAdapter(new Voltage220V()));
}
}
根据合成复用原则,使用组合替代继承, 所以它解决了类适配器必须继承 src 的局限性问题,也不再要求 dst必须是接口。
// 接口
public interface Interface1 {
void m1();
void m2();
void m3();
void m4();
}
public interface Interface2 {
void t1();
void t2();
void t3();
void t4();
}
public class AbstractAdapter implements Interface1 ,Interface2{
// 默认实现
@Override
public void m1() {
}
......
}
// 测试
public class Client {
public static void main(String[] args) {
AbstractAdapter abstractAdapter = new AbstractAdapter() {
// 只需要去覆盖我们需要使用的方法就好了
@Override
public void m1() {
System.out.println("m1 run .... ");
}
@Override
public void t2() {
System.out.println("t2 run ....");
}
};
abstractAdapter.m1();
abstractAdapter.t2();
}
}