设计模式之美7-11

哪些代码设计看似是面向对象,实际是面向过程的

  1. 滥用get和set方法:set方法应该谨慎使用,对于返回值为对象的get方法也应该慎重使用,如果返回值为集合类型,可以使用Collections.unmodifiableList() 方法,返回一个不可修改的集合容器。
  2. 滥用全局变量和方法:
    常见的全局变量:单例类对象、静态成员变量、常量
    常见的全局方法:静态方法
    在定义utils类之前,需要先问自己,是否需要单独定义一个utils类,是否可以吧utils类中的某些方法定义到其他类中?
    定义constants类时,尽量区分不同的constants,或哪个类用到这个常量,就把他定义到哪个类中(如果有多个类使用同一个常量,还是把它放在一个单独的constants类中)
  3. 定义数据和方法分离的类
  4. 面向对象编程中类的设计
  • 你要去思考如何封装合适的数据和方法到一个类里,如何设计类之间的关系,如何设计类之间的交互

接口vs抽象类的区别?如何用普通的类模拟抽象类和接口?

抽象类和接口能解决什么编程问题?

  1. 抽象类:抽象类是为代码复用而生的,多个子类可以继承抽象类中定义的属性和方法,避免在子类中重复编写相同的代码。
  2. 接口:接口侧重于解耦.

如何决定该用抽象类还是接口?

如果要标识一种is-a的关系,并且是为了解决代码复用的问题,我们就用抽象类;如果我们要表示一种has-a关系,并且是为了解决抽象而非代码复用的问题,那我们就可以使用接口.从类的继承层次来看,抽象是一种自下而上的设计思路,先有子类的代码复用,然后再抽象成上层的父类.

理论六:为什么基于接口而非实现编程?有必要为每个类都定义接口吗?

如何解读原则中的“接口”二字?

越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性,越能应对未来的需求变化。好的代码设计,不仅
能应对当下的需求,而且在将来需求发生变化的时候,仍然能够在不破坏原有代码设计的情况下灵活应对。而抽象就是提高代码扩展性、灵活性、可维护性最有效的手段之一。

如何将这条原则应用到实战中?

  1. 函数的命名不能暴露任何实现细节,比如,前面提到的uploadToAliyun()就不符合要求,应该改为去掉aliyun这样的字眼,改为更加抽象的命名方式,比如:upload().
  2. 封装具体的实现细节.比如,跟阿里云相关的特殊上传(或下载)流程不应该暴露给调用者.我们对上传(或下载)流程进行封装,对外提供一个包裹所有上传(或下载)细节的方法,给调用者使用.
  3. 为实现类定义抽象的接口.具体的实现类都依赖统一的接口定义,遵从一致的上传功能协议.使用者依赖接口,而不是具体的实现类来编程.
    总结一下,我们在做软件开发的时候,一定要有抽象意识、封装意识、接口意识。在定义接口的时候,不要暴露任何实现细节。接口的定义只表明做什么,而不是怎么做。而且,在设计接口的时候,我们要多思考一下,这样的接口设计是否足够通用,是否能够做到在替换具体的接口实现的时候,不需要任何接口定义的改动。

是否需要为每个类定义接口?

**这条原则的设计初衷是,将接口和实现相分离,封装不稳定的实现,暴露稳定的接口。**从这个设计初衷上来看,如果在我们的业务场景中,某个功能只有一种实现方式,未来也不可能被其他实现方式替换,那我们就没有必要为其设计接口,也没有必要基于接口编程,直接使用实现类就可以了。

理论七:为何说要多用组合少用继承?如何决定该用组合还是继承?

  1. 继承的缺点:继承层次过深、继承关系过于复杂会影响到代码的可读性和可维护性。这也是为什么我们不推荐使用继承。
  2. 继承主要有三个作用:表示 is-a 关系,支持多态特性,代码复用。而这三个作用都可以通过组合、接口、委托三个技术手段来达成。

组合相比继承有哪些优势?

通过组合和委托的技术来消除代码重复,具体的代码实现如下:

public interface Flyable {
	void fly()}
public class FlyAbility implements Flyable {
	@Override
	public void fly() { //... }
}
// 省略 Tweetable/TweetAbility/EggLayable/EggLayAbility
public class Ostrich implements Tweetable, EggLayable {// 鸵鸟
	private TweetAbility tweetAbility = new TweetAbility(); // 组合
	private EggLayAbility eggLayAbility = new EggLayAbility(); // 组合
	//... 省略其他属性和方法...
	@Override
	public void tweet() {
		tweetAbility.tweet(); // 委托
	}
	@Override
	public void layEgg() {
		eggLayAbility.layEgg(); // 委托
	}
}

如何判断该用组合还是继承?

如果类之间的继承结构稳定(不会轻易改变),继承层次比较浅(比如,最多有两层继承关系),继承关系不复杂,我们就可以大胆地使用继承。反之,系统越不稳定,继承层次很深,继承关系复杂,我们就尽量使用组合来替代继承。
如果仅仅是为了抽出像的部分,而且类和类之间没有层次关系,则应该使用组合

public class Url {
	//... 省略属性和方法
}
public class Crawler {
	private Url url; // 组合
	public Crawler() {
	this.url = new Url();
	}
	//...
}
public class PageAnalyzer {
	private Url url; // 组合
	public PageAnalyzer() {
		this.url = new Url();
	}
	//..
}

实战一(上):业务开发常用的基于贫血模型的MVC架构违背OOP吗?

mvc三层架构是一个失血模型,违反了面向对象编程的风格,在领域驱动设计盛行后,这种基于贫血模型的传统开发的开发模式就被人诟病.而基于充血模型的DDD开发模式越来越被人提倡.
什么是贫血模型?
贫血模型将数据和操作分离,破坏了面向对象的封装特性,是一种典型的面向过程的编程风格.

什么是基于充血模型的 DDD 开发模式?

  1. 什么是充血模型:数据和对应的业务逻辑被封装到同一个类中.因此,这种充血模型满足面向对象的封装特性,是典型的面向对象的编程风格.
  2. 什么是领域驱动设计(DDD):主要是用来周到如何解耦业务系统,划分业务模块,定义业务领域模型及其交互.
  3. 实际上,基于充血模型的DDD开发模式实现的代码,也是按照MVC三层架构分层的.controller层,repository曾层,service层.他跟贫血模型的传统开发模式的区别主要在service层.
    在基于充血模型的 DDD 开发模式中,Service 层包含 Service 类和 Domain 类两部分。Domain 就相当于贫血模型中的 BO。不过,Domain 与 BO 的区别在于它是基于充血模型开发的,既包含数据,也包含业务逻辑。而 Service 类变得非常单薄。总结一下的话就是,基于贫血模型的传统的开发模式,重 Service 轻 BO;基于充血模型的 DDD 开发模式,轻 Service 重
    Domain。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值