设计模式之禅-思考上

6大基本原则

程序是面向现实的抽象。

单一职责:类的功能尽量单一,职责单一,只干一类事情。应该有且仅有一个原因引起类的变更。这个要根据实际项目来设计 类的职责。尽量做到单一。
里式替换 :所有引用基类的地方必须能透明的使用其子类的对象。就是说 有可能变化的地方,和耦合的地方 尽量使用 接口或者抽象父类 声明参数。这样后期容易修改。
依赖倒置 :高层模块不应该依赖低层模块,两者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。高层模块和低层模块容易理解,每一个逻辑的实现都是由原子逻辑组成的,不可分割的原子逻辑就是低层模块,原子逻辑的再组装就是高层模块。就是说 类与类之间的依赖关系(有6大关系1.继承2实现3.关联4依赖5聚合6组合) 尽量避免直接依赖,而应该依赖其接口或者父类。依赖注入的3种写法:1.构造函数传递依赖对象。2.Set方法中传递依赖对象。3.接口声明依赖对象。
接口隔离 :类间的依赖关系应该建立在最小的接口上。这个我也理解都不是特别清楚,只能说设计接口的时候 不要搞一个很大的接口,然后大家都来实现,结果很多都是空实现。应该根据需要,单一等因素设计 合适大小的接口、
迪米特原则 :也叫最小知道原则。一个对象应该对其他对象有最少了解。或者说 只与直接的朋友通信。朋友类的定义是:出现在成员变量,方法的输入输出参数中的其他类称为该类的朋友类。另一方面也是一个类尽量不要对外公布太多的public方法和非静态的public变量。尽量内敛,多使用private package-private protected等访问权限。如果一个方法放到本类总,既不增加类间关系,也对本类不产生负面影响,那就放置在本类中。迪米特法则的核心管理就是类间解耦,弱耦合。
开闭原则 :最重要的一个原则。一个软件实体如类,模块和函数应该对扩展开放,对修改关闭。怎么样才能做到以上 那就要上面的5个原则都是为此服务。1.抽象约束2.元数据控制模块行为3.封装变化。测试:1.正常测试2边界测试3异常测试

23种设计模式

单例模式:使此类在程序运行只有一个对象。
构造函数设置为private,原理:静态修改的变量叫做类变量,简单的说就是这个变量是和类在一起的。不管你new多少个这个类的对象,这个类变量只有一份。它存储在内存中的方法区。创建单例模式有很多种方式,我最喜欢用的是 静态内部类实现单例如:

	//提供给外部的方法
	public static Data getInstance() {
		return DataHolder.sInstance;
	}
	//静态内部类
	public static class DataHolder {
		public static Data sInstance = new ConnectSerial5();
	}
	//私有构造函数
	private Data () {
	}

这个方式的好处是保证单例的唯一,对象的创建和类的初始化一起,根据类加载原则,类只会加载一次。类图比较简单:
在这里插入图片描述

工厂方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
一般我们创建对象都是直接new。但是这样会有一个不好,就是当需要创建的类的构造函数发生改变,那么高层用户也需要改变。这样不利解耦,所以在中间加一层,专门管理这个类的对象创建。如:

public static void main(String[] args) {
		//通常创建对象
		AAA aaa=new AAA();
		//使用简单工厂创建对象
		AAA bbb=SingleFactory.getInstance();
	}
public class SingleFactory {
	public static AAA getInstance(){
		return new AAA();
	}
}

当然这只是最简单的写法。还有很多变形的写法,但是核心就是增加了一个factory类管理对象的创建。不过也不要什么对象都通过工厂创建,我认为只有一组很类似的对象创建才需要,如,创建香蕉,苹果,橘子 等。就可以创建一个水果工厂管理创建。其通用类图如下:
在这里插入图片描述

抽象工厂:为一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类。
抽象工厂的UML类图和工厂方法是一样的。以下是我对这2个模式的理解:
根据定义抽象工厂是为一组相关或者相互依赖的对象提供接口,而工厂方法并没这么说,只是说为一个对象的创建提供接口,就是说抽象工厂是有限制条件的,相关或者相互依赖。例如上面工厂方法中的水果,苹果和香蕉是没什么相关性的,只是同属水果,但是这个太广泛,太大了。
那哪些对象可以说是有相关的,海南香蕉和越南香蕉就是一组相关的对象。都是香蕉,只不过是按地域分的,无籽香蕉和有籽香蕉也是相关的。
那哪些对象可以说是有相互依赖的,车的左门和右门。男人和女人。
总结:总的来说 工厂方法和抽象工厂 功能都是一样的,增加一个中间层factory管理对象的创建。不同的是 对创建对象的分类定义上有所以不同,简单工厂无限制,抽象工厂是针对一组相关或者相互依赖对象提供接。所以这些差别就反应在工厂接口中定义的方法:
举个栗子:以水果 苹果 香蕉为例:
工厂方法:

//水果的抽象类
public abstract class abstractFruit {
	abstract void eat();
}
public class Apple extends abstractFruit {
	void eat() {
		System.out.println("我是苹果");
	}

}
public class Banana extends abstractFruit {
	void eat() {
		System.out.println("我是香蕉");
	}
}
//简单工厂抽象类
public interface ISingleFactory {
	abstractFruit  createFruit(String clsName);
}
简单工厂实现类-这里为了简单采用反射创建对象
public class SingleFactory implements ISingleFactory {
	@Override
	public abstractFruit createFruit(String clsName) {
		abstractFruit fruit = null;
		try {
			fruit = (abstractFruit) Class.forName(clsName).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return fruit;
	}
}
public static void main(String[] args) {
		ISingleFactory singleFactory = new SingleFactory();
		abstractFruit apple = singleFactory.createFruit("com.zx.test.factory.Apple");
		apple.eat();
		abstractFruit banana = singleFactory.createFruit("com.zx.test.factory.Banana");
		banana.eat();
	}

运行结果:
在这里插入图片描述
抽象工厂:

public class AppleBlue extends abstractFruit {
	void eat() {
		System.out.println("我是蓝色苹果");
	}

}
public class AppleRed extends abstractFruit {
	void eat() {
		System.out.println("我是红色苹果");
	}

}
public class BananaBlue extends abstractFruit {
	void eat() {
		System.out.println("我是蓝色香蕉");
	}
}

public class BananaRed extends abstractFruit {
	void eat() {
		System.out.println("我是红色香蕉");
	}
}
//工厂抽象类
public interface IAbstractFactory {
	
	abstractFruit  createApple();
	
	abstractFruit  createBanana();
}
//生产红色水果工厂
public class RedAbstractFactory implements IAbstractFactory {

	@Override
	public abstractFruit createApple() {
		return new AppleRed();
	}
	@Override
	public abstractFruit createBanana() {
		return new BananaRed();
	}
	
}
//生产蓝色水果工厂
public class BlueAbstractFactory implements IAbstractFactory {

	@Override
	public abstractFruit createApple() {
		return new AppleBlue();
	}
	@Override
	public abstractFruit createBanana() {
		return new BananaBlue();
	}
	
}
//测试
public static void main(String[] args) {
		//工厂方法
		ISingleFactory singleFactory = new SingleFactory();
		abstractFruit apple = singleFactory.createFruit("com.zx.test.factory.Apple");
		apple.eat();
		abstractFruit banana = singleFactory.createFruit("com.zx.test.factory.Banana");
		banana.eat();
		System.out.println("-----------------------------------");
		//抽象工厂
		IAbstractFactory abstractFactoryRed=new RedAbstractFactory();
		abstractFruit appleRed = abstractFactoryRed.createApple();
		appleRed.eat();
		abstractFruit bananaRed = abstractFactoryRed.createBanana();
		bananaRed.eat();
		IAbstractFactory abstractFactoryBlue=new BlueAbstractFactory();
		abstractFruit appleBlue = abstractFactoryBlue.createApple();
		appleBlue.eat();
		abstractFruit bananaBlue = abstractFactoryBlue.createBanana();
		bananaBlue.eat();
	}

结果:
在这里插入图片描述
总结:通过这个2个例子可以看出,抽象工厂和工厂方法的区别,是需求不同导致工厂接口的方法不同。所以 要根据你具体的需求来确定。比如上面的水果,你需求是要香蕉,苹果,橘子,西瓜等等 那就用工厂方法。如果你需求是 要 蓝色香蕉,蓝牙苹果,蓝色橘子。红色香蕉,红色苹果,红色橘子 等 是一组相关的产品那就用抽象工厂。

模板方法:定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤。
为了防止恶意的操作,一般模板方法都加上final关键字,不允许被覆写。
模板方法比较简单 以一个人个的一天为例:

// 定义一个父类,人一天的生活
public abstract class AbstractPeople {
	void rise() {
		System.out.println("起床");
	}

	void eat() {
		System.out.println("吃饭");
	}

	abstract void work();

	void sleep() {
		System.out.println("睡觉");
	}

	// 打印一天
	public final void onDay() {
		rise();
		eat();
		work();
		sleep();
	}
}
public class AdultPeople extends AbstractPeople {

	@Override
	void work() {
		System.out.println("赚钱");
	}
}
public class StudentPeople extends AbstractPeople {

	@Override
	void work() {
		System.out.println("读书");//学生的工作就是读书
	}
}
public static void main(String[] args) {
		AbstractPeople adult=new AdultPeople();
		adult.onDay();
		System.out.println("---------------------------");
		AbstractPeople student=new StudentPeople();
		student.onDay();
	}

运行结果:
在这里插入图片描述
通用的类图:
在这里插入图片描述
这里还有一个常用的技巧就是设置一个钩子。如正常人每天都需要赚钱,但是富二代不用啊,即可以改成如下:
在这里插入图片描述
在这里插入图片描述

建造者 :将一个复杂对象的构建与它的表示分离,使得构建过程可以创建不同的表示。
这个和工厂模式很像,都是添加中间层去管理对象的创建,但是建造者和工厂 的侧重点不同,工厂侧重整体创建,建造者侧重 部分,就是创建的过程,流程和 拼装的部分。还是以上面创建水果对象为例,不知道对不对,:

public interface Apple {
	void eat();
	void setColor(String color);
}
public class ConcreteApple implements Apple {

	private String color = "红色";

	@Override
	public void setColor(String color) {
		this.color = color;
	}

	@Override
	public void eat() {
		System.out.println("我是" + color + "苹果");

	}

}

public interface AppleBuilder {
	void setColor(String color);

	Apple getApple();
}
public class ConcreteBuilder implements AppleBuilder {

	private Apple appleA = new ConcreteApple();

	@Override
	public Apple getApple() {
		return appleA;
	}

	public void setColor(String color) {
		appleA.setColor(color);
	}
}
public class Director {

	private ConcreteBuilder appleBuilder = new ConcreteBuilder();

	public Apple getAppleA() {
		appleBuilder.setColor("黑色");
		return appleBuilder.getApple();
	}
	public Apple getAppleB() {
		appleBuilder.setColor("黄色");
		return appleBuilder.getApple();
	}
}
public static void main(String[] args) {
		Director director = new Director();
		//来个A类型的苹果
		director.getAppleA().eat();
		//来个B类型的苹果
		director.getAppleB().eat();
	}

运行结果:
在这里插入图片描述
总结:核心思想就是 增加一个建造层,屏蔽 高层用户 对 具体产品的 细节。如上,苹果是产品,有颜色的区别,A类苹果是黑色,B类苹果是黄色。如果我们不增加中间层,直接new的话就是如下:

public static void main(String[] args) {
		Apple apple=new ConcreteApple();
		apple.setColor("黑色");
		apple.eat();
		System.out.println("-------------------------------");
		Director director = new Director();
		//来个A类型的苹果
		director.getAppleA().eat();
		//来个B类型的苹果
		director.getAppleB().eat();
	}

虽然运行结果是一样,但是用户还要自己去设置苹果的颜色,显然是不合理的,这个属性是不应该让用户去知晓的。增加了建造者就不同,用户只要说给我一个A类苹果就行了。
具体类图:
在这里插入图片描述
苹果就是产品类。
代理模式:为其他对象提供一种代理以控制对这个对象的访问。也叫委托模式。
代理模式比较简单,想象成皮包公司就好了。

public interface IEat {
	void eat();
}

public class ConcreteEat implements IEat{

	@Override
	public void eat() {
		System.out.println("表演用手吃饭");
	}
	
}
public class EatProxy implements IEat {
	private IEat eat = new ConcreteEat();
	@Override
	public void eat() {
		this.eat.eat();
	}
}
public class ProxyTest {
	public static void main(String[] args) {
		IEat proxy = new EatProxy();
		proxy.eat();
	}
}

运行结果:
在这里插入图片描述
可以看到 客户端根本就不知道 具体的吃类,知道代理,但是最终干活的不是代理,记住 代理=皮包公司 皮包公司是没有生成产品的能力的。
类图:
在这里插入图片描述
代理模式可以扩展出:
普通代理:要求客户端只能访问代理角色,而不能访问真实角色。
强制代理:通过真实角色找到代理角色。
动态代理:AOP面向横切面编程、实现InvocationHandler接口。切面Aspect,切入点JoinPoint,通知advice,织入Weave.
原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。实现Cloneable接口,重写clone方法。
原型模式比较简单就是利用对象的clone方法复制对象,已达到快速创建对象的目的。
简单实现:

public class Apple implements Cloneable{
 String name;
 void eat(){
  System.out.println("我是"+name+"水果!");
 }
 void setName(String name) {
  this.name=name;
 }
 @Override
 protected Object clone(){
  Apple fruit=null;
  try {
   fruit=(Apple) super.clone();
  } catch (CloneNotSupportedException e) {
   e.printStackTrace();
  }
  return fruit;
 }
}
public static void main(String[] args) {
  Apple appleA=new Apple();
  appleA.setName("红苹果");
  appleA.eat();
  Apple appleB=(Apple) appleA.clone();
  appleB.setName("青苹果");
  appleB.eat();
 }

运行结果:
在这里插入图片描述
可以看到我们第二个对象不是通过new出来的。这里可以引申出对象的创建有
1.new
2.clone克隆
3.newInstance反射
4.parcel/Serializable反序列化
基本类图:
在这里插入图片描述
注意事项:使用clone 类的构造函数不会执行。2浅拷贝,深拷贝。对象内部的数组,引用对象不会拷贝,还是指向原生对象的内部元素地址,这就是浅拷贝。深拷贝也很简单就是数组对象也都自己拷贝一遍如:
在这里插入图片描述

3.不用使用final关键字。

中介者模式:用一个中介对象封装一系列的对象交互,中介使用个对象不需要显示的相互作用,从而使其耦合松散,而且可以独立的改变它们之间的交互。
核心就是增加一个类处理公共的事情。就是本来A做一件事情a()需要从B获取信息然后处理。B中做一件事情b()需要从A获取信息然后处理。但是A和B是同级类 且没什么联系。
这个时候我们就可以增加一个C类,C类持有A,B,A.B持有C,然后当前A需要做a()时,直接交给C去执行。除了书中的 销售 库存 采购 暂时想不起其他例子。。。
类图:
在这里插入图片描述

在这里插入图片描述
但是这种模式缺点也很明显就是 中介者这个类 会越来越大,而且这个模式,引用都是具体实现 违反了 里氏替换,依赖倒置等
由于字数限制,只能转下一篇。

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《设计模式之禅第3版pdf》是一本介绍设计模式的书籍,是作者秦小波总结多年编程和软件开发实践的经验而得出的结论。该书提供了许多实用的设计模式,这些模式可以帮助开发人员更好地编写可维护、可扩展和可重用的代码。 该书首先介绍了设计模式的基本概念和原则,例如SOLID原则和GRASP原则,然后详细介绍了23种常见的设计模式,包括创建型、结构型和行为型模式。 该书的优点在于,它不仅提供了许多具体的代码示例和实际应用场景,还深入解释了每个模式的原理和适用条件。此外,该书还提供了设计模式的演化历程,以及如何使用UML图形表示不同的模式。 虽然该书提供了丰富的知识,但它并不是一本初学者可以轻松掌握的书籍。初学者可能需要花费很多时间和精力来理解书中的概念和代码实例。与此同时,该书的代码示例使用Java语言,因此对于非Java开发人员可能需要适当地进行转换。 综上所述,《设计模式之禅第3版pdf》是一本非常有价值的设计模式书籍,对于希望提高代码质量和扩展性的开发人员来说,是一本必读之作。 ### 回答2: 《设计模式之禅第3版》是一本关于对象设计模式的经典著作,是程序员学习设计模式的一本不可或缺的参考书。该书共分为3部分,包含了23种设计模式,并以生动的例子和详细的代码展示了如何应用各种设计模式解决实际问题。 第一部分介绍了7种创建型模式,这些模式主要用于创建对象。其中包括了工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式、享元模式和对象池模式。通过这一部分的学习,读者可以了解到如何灵活地创建对象,避免了对象创建过程中出现的一些问题。 第二部分介绍了11种结构型模式,这些模式主要用于组织类和对象。其中包括了适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式、代理模式、管道过滤器模式、私有类数据模式、模板方法模式和访问者模式。通过这一部分的学习,读者可以学会如何组织各种不同类和对象之间的关系,从而更加有条理地编写代码。 第三部分介绍了5种行为型模式,这些模式主要用于管理对象之间的交互和职责。其中包括了责任链模式、命令模式、解释器模式、迭代器模式和观察者模式。通过这一部分的学习,读者可以学会如何精确地定义对象之间的互动和职责,从而更好地解决实际问题。 总体而言,《设计模式之禅第3版》由浅入深,结构清晰,用通俗易懂的语言阐述了设计模式的本质和应用,是程序员进行设计模式学习和应用的一本宝典。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值