【设计模式】Object Oriented面向对象思想剖析

简介:
OO思维(Object Oriented以对象为方向)
这里以"老张开车去东北"为例子。

创建一个ThinkInOO的工程:

先来看看小明的非面向对象思维的工程:
package cn.edu.ThinkInOO;


public class Test1 {
	public static void main(String[] args) {
		System.out.println("老张开车去东北");
	}
}


是不是没什么属性呢?于是他又改了:
package cn.edu.ThinkInOO;


public class Test2 {
	public static void main(String[] args) {
		String driverName="老张";
		String vehicle="车";
		String tergetPlace="东北";
		System.out.println(driverName+"开"+vehicle+"去"+tergetPlace);
	}
}


小刚问:“为什么连个方法也没有啊?”,小明想想也是,于是加了:
package cn.edu.ThinkInOO;


public class Test2 {
		public static void main(String[] args) {
				String driverName="老张";
				String vehicle="车";
				String tergetPlace="东北";
				go( driverName,vehicle,tergetPlace);
		}
		
		public static void go(String driverName,String vehicle,String tergetPlace){
			System.out.println(driverName+"开"+vehicle+"去"+tergetPlace);
		}
}
这样设计真的可以吗?答案肯定是否定的。

很多初学者设计程序都是非常非常简单,从来都是一个main方法就搞定了,就算他组织一个类,
很可能在一个类里一个方法200多行把所有功能全包括了,其实这就有点用面向过程出的思想去写
面向对象了。
要知道“方法”是封装的第一步。什么是封装?封装就是把一些功能放到特定的地方去,将来大
家调用的时候不需要去看里面的内容,只需要看类名、方法名就可以了。
封装是编程思想中复用的第一步。

面向对象的三个思想:封装、继承和多态。

回来看问题:定了半天,所有类都是Test,可不可以让它分解成类(class)呢?这就是面向对象的

第一步:

1.考虑类
名词:可以设置为类的属性,符合类条件的鲜明的特征都可以定义为类的名字。
下面我们开始进行"老张开车去东北"的类的封装:
我们封装3个类,分别是:Driver.java、Car.java、Address.java(司机、车型、地址)
Driver.java:
package cn.edu.ThinkInOO;


public class Driver {
		
}
Car.java:
package cn.edu.ThinkInOO;


public class Car {


}
Address.java:
package cn.edu.ThinkInOO;


public class Address {


}


2.属性
不可脱离具体的应用环境

定义完类之后,我们需要为每一个类定一些属性,对于任何一个类,都不能脱离具体的应用环境,

要根据具体的应用环境去顶我们的属性,跟我们没关系的属性我们不要去封装。

下面是这三个类的属性封装:
Driver.java:
package cn.edu.ThinkInOO;


public class Driver {
    String DriverName;
}

Car.java:
package cn.edu.ThinkInOO;


public class Car {
    String carType;
}


Address.java:
package cn.edu.ThinkInOO;


public class Address {
    String addressName;
}

3.方法
下面我们来定义类的方法:
首先,司机肯定有一个开车的方法:
package cn.edu.ThinkInOO;


public class Driver {
		String DriverName;
		
		public void driver(){
			
		}
}


车有一个行驶的方法:
package cn.edu.ThinkInOO;


public class Car {
		String Type;
		
		public void go(){
		
		}
}

目的地类暂时没有方法


下面我们设置一些访问权限来保护属性的安全(private和get、set方法)
Car.java:
package cn.edu.ThinkInOO;

public class Car extends Vihecle{
		private String Type;
	
		public String getType() {
			return Type;
		}


		public void setType(String Type) {
			this.Type = Type;
		}


		public void go(Address dest){
		
		}
}
Driver.java:
package cn.edu.ThinkInOO;


public class Driver {
		private String DriverName;
		
		public String getDriverName() {
			return DriverName;
		}


		public void setDriverName(String driverName) {
			DriverName = driverName;
		}


		public void driver() {


		}
}
Address.java:
package cn.edu.ThinkInOO;


public class Address {
		private String addressName;
		
		public String getAddressName() {
			return addressName;
		}


		public void setAddressName(String addressName) {
			this.addressName = addressName;
		}
		
		
}


4.类之间的关系(依赖,继承,聚合)
写好了上面的东西,我们来执行"老张开车去东北"
写一个"Travel"(旅游)的测试类:
package cn.edu.ThinkInOO;


public class Travel {
		public static void main(String[] args) {
			Driver d=new Driver();
			d.setDriverName("老张");
			d.driver();
		}
}

写到这,就要考虑司机和车的关系了,driver老张和Car车如何联系?这就考虑类与类之间的关系了。


我们可以把Car设为Driver的一个私有变量,也可以将Car作为参数传入Driver的driver方法中。


这里我们采用后者:
package cn.edu.ThinkInOO;


public class Driver {
		String DriverName;
		
		public void driver(Car c){


		}
}


5.隐藏(封装)
降低耦合度。
什么叫耦合度?假如你盖了个房子,现在想在房子旁边盖一个配房,如果你盖配房的时候需要把
主房的门窗柱子拆下来改,这说明原来房子设计的不好。哪不好?新的功能和老的功能之间的耦
合度太强了,耦合就是连在一起的,牵一发而动全身,我要添加新功能的时候,我居然要把原来
的功能改一遍,说明设计的不好。我要把窗户从方的改成圆的我就要把所有墙重新做,说明耦合
度太强了。这样做肯定不合理,改窗户只和窗户或那面墙有关系,耦合度不可能100%,但是我们可

以将耦合度降到合适的程度。


所以在Driver类中的driver方法里,我们传入了Car,对于Car如何行使,我们只在Car类中去设置,而和Driver类没有任何关系

package cn.edu.ThinkInOO;


public class Driver {
		String DriverName;
		
		public void driver(Car c){
		    c.go();
		}
}
属性private,读取用get与set是隐藏与封装,
尽量把对方该做的事情让对方自己去做这也是隐藏与封装。


6.站在使用者的角度思考
我们开车要去哪呢?地址可以设置成Car的go方法的参数:
package cn.edu.ThinkInOO;


public class Car {
		private String Type;
		
		public String getType() {
			return Type;
		}


		public void setType(String Type) {
			this.Type = Type;
		}


		public void go(Address dest){
			System.out.println(Type+"一路加着速,疾驰至"+dest.getAddressName());
		}
}
给Address加了构造方法来传参数:
package cn.edu.ThinkInOO;


public class Address {
		private String addressName;


		Address(){
			
		}
		
		Address(String dest){
			this.setAddressName(dest);
		}
		
		public String getAddressName() {
			return addressName;
		}


		public void setAddressName(String addressName) {
			this.addressName = addressName;
		}
		
		
}


司机类:
package cn.edu.ThinkInOO;


public class Driver {
		private String DriverName;
		
		public String getDriverName() {
			return DriverName;
		}


		public void setDriverName(String driverName) {
			DriverName = driverName;
		}


		public void driver(Car c){
			c.go(new Address("东北"));
		}
}
测试类;
package cn.edu.ThinkInOO;

public class Travel {
		public static void main(String[] args) {
			Driver d=new Driver();
			d.setDriverName("老张");
			d.driver(new Car());
		}
}

但是你有没有发现,我们无法从测试程序告知司机目的地是哪,只能指定开什么车去。
这就需要当你设计一个类的方法,应该站在使用者的角度去设计,去考虑需求。

那么类就需要"扩展"。
扩展后的Driver:
package cn.edu.ThinkInOO;


public class Driver {
		private String DriverName;
		
		public String getDriverName() {
			return DriverName;
		}


		public void setDriverName(String driverName) {
			DriverName = driverName;
		}


		public void driver(Car c){
			c.go(new Address("东北"));
		}
		
		public void driver(Car c,Address dest){
			c.go(dest);
		}
}
“重载”了driver方法,加了目的地的属性。


6.继承
如果老张开飞机去不开汽车去怎么办?
小明第一个想到的就是再写一个Plane.java的类,在重载driver方法,给它加上Plane的参数,并
完成目的地的指定。这种方法没有问题,可以这么设计,但是,有没有更好的设计方法呢?如果
我开轮船呢?做滑翔机呢?难道每次都要重写一个类,然后重载driver方法,然后重新指定
driver的参数?那样不仅麻烦,而且代码冗余度很高。

这里我们可以用继承的方式来解决这个问题,提升程序的拓展性。
我们为所有交通工具设置一个父类交通工具类Vihecle.java:
package cn.edu.ThinkInOO;


public class Vihecle {
	
}
我们写一个飞机类继承Vihecle,并把Car也继承Vihecle。
package cn.edu.ThinkInOO;


public class Plane extends Vihecle{
	private String Type;
	
	public String getType() {
		return Type;
	}


	public void setType(String Type) {
		this.Type = Type;
	}


	public void go(Address dest){
		System.out.println(planeType+"一路转着螺旋桨,翱翔至"+dest.getAddressName());
	}
}

Car.java:
package cn.edu.ThinkInOO;


public class Car extends Vihecle{
		private String Type;
		
		public String getType() {
			return Type;
		}


		public void setType(String Type) {
			this.Type = Type;
		}


		public void go(Address dest){
			System.out.println(carType+"一路加着速,疾驰至"+dest.getAddressName());
		}
}

在driver中就可以这么写:
package cn.edu.ThinkInOO;


public class Driver {
		private String DriverName;
		
		public String getDriverName() {
			return DriverName;
		}


		public void setDriverName(String driverName) {
			DriverName = driverName;
		}
		
		public void driver(Vihecle v,Address dest){
			
		}
}
只需要一个driver方法即可满足所有交通工具。
只要你能说通这句话,就可以考虑使用继承:"什么什么是一种什么什么"
继承关系由于耦合度非常强,应该谨慎使用。


7.多态(核心)
好处:可拓展性
三个特性:有继承、有重写、有父类引用指向子类对象。
多态是什么意思呢?上面我们定义了driver方法,但是没有写方法内容,我们如何使用传入进来
的Vihecle类?如果判断类型的话,拓展性依旧没变化。我们可以这样:
在Vihecle里定义一个go方法。
那么go方法如何让实现呢?不知道工具类型,所以不需要实现。
我们把方法和类设置成抽象(abstract)的
package cn.edu.ThinkInOO;


public abstract class Vihecle {
		private String Type;
		
		public String getType() {
			return Type;
		}


		public void setType(String Type) {
			this.Type = Type;
		}


		public abstract void go(Address dest);
}
Driver类:
package cn.edu.ThinkInOO;


public class Driver {
		private String DriverName;
		
		public String getDriverName() {
			return DriverName;
		}


		public void setDriverName(String driverName) {
			DriverName = driverName;
		}
	
		public void driver(Vihecle v,Address dest){
		        System.out.print(DriverName+"驾驶着");
			v.go(dest);
		}
}


那么Car与Plane都继承了Vihecle类,都重写了Vihecle的go方法。
那么当我们向Driver类的driver方法传递任何Vihecle的子类的时候,你传的是谁,就调用的谁的


go方法,这就是多态。
测试:
package cn.edu.ThinkInOO;


public class Travel {
		public static void main(String[] args) {
			Driver d=new Driver();
			d.setDriverName("老张");
			Vihecle c=new Car();
			c.setType("法拉利");
			d.driver(c,new Address("东北"));
			
			d.setDriverName("老李");
			Vihecle p=new Plane();
			p.setType("战斗机");
			d.driver(p,new Address("美国"));
		}
}

测试结果:
老张驾驶着法拉利一路加着速,疾驰至东北
老李驾驶着战斗机一路转着螺旋桨,翱翔至美国

至此,面向对象的思想全部介绍完毕!

注意:
1.设计没有绝对的对与错
2.Over Design也是一种罪过
3.没有任何实际中的设计会一步到位

4.初学者不要考虑太多的原则和条条框框,最重要是动手写


举个例子:抽象类与接口的区别:
如果你是考虑一些有共同特征的事物,我们就设计接口。
如果你对特征比较模糊,就用抽象类。
而且类一次只能继承一个类,而可以实现多个接口。

5.享受编程的乐趣吧

结语:
O O 思想慢慢来
封装继承和多态
设计层层无止境
适可而止乐开怀


留的作业:
农场一头小母牛,
每年生头小母牛,
母牛五岁产母牛,
二十年上多少牛?
请用面向对象的思想来解决这个问题。
我写的母牛作业在下面这篇文章里: http://blog.csdn.net/acmman/article/details/43817323

知识点总结于马士兵老师的"设计模式"视频,感谢尚学堂的共享。

转载请注明出处:http://blog.csdn.net/acmman

相关文章
|
3月前
|
设计模式 数据库连接 PHP
PHP编程中的面向对象与设计模式
在PHP编程世界中,掌握面向对象编程(OOP)和设计模式是提升代码质量和开发效率的关键。本文将深入浅出地介绍如何在PHP中应用OOP原则和设计模式,以及这些实践如何影响项目架构和维护性。通过实际案例,我们将探索如何利用这些概念来构建更健壮、可扩展的应用程序。
|
6月前
|
设计模式 算法 架构师
【搞懂设计模式】设计模式与面向对象原则
【搞懂设计模式】设计模式与面向对象原则
65 1
|
5月前
|
设计模式 存储 Java
JavaSE——面向对象高级二(2/4)-final关键字、常量、抽象类(认识抽象类、抽象类的好处、应用场景-模板方法设计模式)
JavaSE——面向对象高级二(2/4)-final关键字、常量、抽象类(认识抽象类、抽象类的好处、应用场景-模板方法设计模式)
28 0
|
6月前
|
设计模式 Java API
【设计模式】JAVA Design Patterns——Active Object(活动对象设计模式)
【设计模式】JAVA Design Patterns——Active Object(活动对象设计模式)
|
6月前
|
设计模式 Java 编译器
Java 设计模式最佳实践:一、从面向对象到函数式编程
Java 设计模式最佳实践:一、从面向对象到函数式编程
104 0
|
设计模式 算法 关系型数据库
设计模式——设计模式简介、分类及面向对象设计原则
23 种设计模式中有些模式今天已经不流行了,有些模型已经被语言机制替代了,有些模式你可能常常会忘记,但这些都不重要,重要的是设计原则,因为有了这些设计原则,你有可能发明自己的模式,你也可以理解未来千千万万其他领域的模式。
104 1
|
设计模式 算法 C#
28【WinForm】C#实现商场收银软件,从面向过程到面向对象,设计模式的应用
实现商场收银系统从简单的面向过程到面向对象的演变。
168 0
|
设计模式 SQL 开发框架
【Java设计模式 面向对象设计思想】六 再谈MVC贫血模式与DDD领域驱动开发
【Java设计模式 面向对象设计思想】六 再谈MVC贫血模式与DDD领域驱动开发
318 1
|
设计模式 Java
【Java设计模式 面向对象设计思想】五 多用组合少用继承编程
【Java设计模式 面向对象设计思想】五 多用组合少用继承编程
240 0
【Java设计模式 面向对象设计思想】五 多用组合少用继承编程
|
设计模式 算法 Java
Object 类详解--代码块--单例设计模式
Object 类详解--代码块--单例设计模式
55 0

热门文章

最新文章

下一篇
无影云桌面