这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/2021Softwarecodedevelopmenttechnology |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/2021Softwarecodedevelopmenttechnology/homework/11833 |
这个作业的目标 | 结合一些图、表工具,用自己的语言对书的主要内容进行归纳总结,谈谈读书的心得体会 |
参考书籍
- 《大话设计模式》
读书笔记
什么是设计模式?
设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
为什么要学设计模式?
-
设计模式已经成为软件开发人员的“标准词汇”
-
学习设计模式是个人技术能力提高的捷径
-
不用重复发明*,而是可以直接使用现有的
本书的特点
《大话设计模式》这本书写得很生动,很形象,用一个个鲜活的例子把23个设计模式、4个设计原则、1个设计法则诠释的淋漓尽致。而且这些例子都是我们日常生活中经常遇到的事情,贴近生活,通俗易懂,不像以前看过的那些教材那么枯燥无味
书的每一章、每一个设计模式都会对应一个现实生活中的例子,让人想不接受都难,每一个例子都那么贴切,每一个模式的引出都是如此的顺理成章、顺其自然,让人看过后感觉这23种设计模式不是为软件开发而制定的,到更像是我们为人处世的一些法则。
设计原则
- 开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
- 里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科
- 依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
- 接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
- 迪米特法则(Demeter Principle)
一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
- 合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。
设计模式
心得体会
在平时的开发及学习中,我对于设计原则的接触较少,但总体上还是遵循高内聚,低耦合的原则。在设计模式方面,接触和使用得更多的是代理模式和单例模式。
单例模式:
单例模式是最简单的设计模式,单例模式就是整个程序有且仅有一个实例。它拥有一个私有构造函数,这确保用户无法通过new直接实例它。除此之外,该模式中包含一个静态私有成员变量instance与静态公有方法Instance()。Instance()方法负责检验并实例化自己,然后存储在静态成员变量中,以确保只有一个实例被创建。
优点:
-
在内存中只有一个对象,节省内存空间;
-
避免频繁的创建销毁对象,可以提高性能;
-
避免对共享资源的多重占用,简化访问;
-
为整个系统提供一个全局访问点。
缺点:
-
不适用于变化频繁的对象;
-
滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;
-
如果实例化的对象长时间不被利用,系统会认为该对象是垃圾而被回收,这可能会导致对象状态的丢失;
代理模式:
代理模式的目的是为其他对象提供一种代理以控制对这个对象的访问。主要解决在直接访问对象时带来的问题,比如要访问的对象在远程的机器上。在面向对象系统中,有些对象由于对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问的问题,直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
优点:
- 将代理对象与真实被调用的目标对象分离。
- 降低了系统的耦合度,提高了扩展性。
- 可以起到保护目标对象的作用。
缺点: - 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。
- 增加了系统的复杂度。
单例模式
//懒汉式
class Bank{
private Bank(){}
private static Bank instance = null;
public static Bank getInstance() {
//方式一:效率稍差
// synchronized (Bank.class){
// if(instance == null) {
// instance = new Bank();
// }
// return instance;
// }
//方式二:避免了干等的情况,提高效率
if(instance == null){
synchronized(Bank.class){
if(instance == null)
instance = new Bank();
}
}
return instance;
}
}
//饿汉式
class Bank{
private Bank(){
}
private static Bank instance = new Bank();
public static Bank getInstance() {
return instance;
}
}
代理模式
/**
* 静态代理举例:
* 特点:编译期间,代理类和被代理类都被确定下来(未使用反射)
*/
interface ClothFactory{
void produceCloth();
}
//代理类
class proxyClothFactory implements ClothFactory{
private ClothFactory factory;
public proxyClothFactory(ClothFactory factory){
this.factory = factory;
}
@Override
public void produceCloth() {
System.out.println("代理工厂工作");
factory.produceCloth();
System.out.println("代理工厂结束工作");
}
}
//被代理类
class Nike implements ClothFactory{
@Override
public void produceCloth() {
System.out.println("NIke工厂工作");
}
}
public class _01Static {
public static void main(String[] args) {
//创建被代理类对象
Nike nike = new Nike();
//创建代理类对象
proxyClothFactory pro = new proxyClothFactory(nike);
pro.produceCloth();
}
}
/**
* 反射的应用:动态代理
* 使用动态代理需要解决的问题:
* 1.如何根据加载到内存中的被代理类,动态地创建代理类及其对象?
* 2.通过代理类调用方法时,如何动态地调用被代理类中的同名方法?
*/
//接口
interface Human{
String getbelif();
void eat(String food);
}
//被代理类
class superMan implements Human{
@Override
public String getbelif() {
return "我要起飞";
}
@Override
public void eat(String food) {
System.out.println("我要吃:" + food);
}
}
//代理类:主要
class proxyFactory{
//使用此方法返回一个代理类的对象,解决问题1
public static Object getProxyInstance(Object obj){//obj为被代理类的对象
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
}
}
class MyInvocationHandler implements InvocationHandler{
private Object obj;//使用被代理类的对象进行赋值
public void bind(Object obj){
this.obj = obj;
}
//通过代理类对象调用某个方法时,自动调用如下的方法
//将被代理类要执行的方法声明在如下方法中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//参数method:代理类对象调用的方法,此方法也作为被代理类对象调用的方法
//obj:被代理类的对象
Object invoke = method.invoke(obj, args);
//返回值为当前类中invoke()的返回值
return invoke;
}
}
public class _02Proxy {
public static void main(String[] args) {
superMan superMan = new superMan();
Human proxyInstance =(Human) proxyFactory.getProxyInstance(superMan);
String str = proxyInstance.getbelif();
System.out.println(str);
proxyInstance.eat("小笼包");
}
}