一直困惑于:
如何设计写好一个类?
什么样的类算是设计比较的好?
前面学习了软件首要技术革命——管理复杂度,以及设计上的一些原则。
对管理复杂度,我非常崇拜;比较笨同一时间东西太多我跟本关注不来,我非常讨厌复杂的事情,
写程序我讨厌太长的函数太大的类太杂乱的逻辑。
学习原则显得非常的散乱和太具理论性不具操作性;而我工作中用的最多还是如何设计写好一个类和多个类之间交互性的问题。
在这个问题上:我时常感觉到只是一种随意性的想当然操作,写一个类仅仅是为了满足当下的需求和应用,通常也只是自己使用和维护;
不用去考虑信息隐藏\封装\继承\扩展\耦合\内聚等。如果一个类不能满足要求时,要做的就是去修改这个类,直到它满足要求为止:
函数功能不满足修改函数功能,类功能不满足增加一个方法来满足等,结果就是问题可以解决,但是代码或结构乱的一团糟;
这期间根本不用去考虑类的任何设计原则和约束,在语法范围完成需要的功能即可。
但是我时常有种感觉这样做是不行的,你比需让你的代码写的友好有原则有规范性便于控制,
保持与平台设计一致的规范性写出自己的风格来。
为何有这种感觉呢?
1)对工作的认识理解越来越深刻
软件开发首要技术革命——管理复杂度;复杂的事情如果无序迟早会出乱子,永远不变的就是变化。
2)良好的设计造就伟大的软件产品诞生
设计模式到底有何用呢?通过近来一段时间平台学习,可以随处可见代码中相关设计模式的使用,
感觉很实用很优雅很美妙,那么为何要如此设计呢,值得思考和学习。
3)阅读别人的代码
太乱的代码是任何都不愿意阅读的,纵横交错的关系,你想改变都难,更难的是你还得跟着他们一块乱,同流合污还是有些痛苦。
4)做些有比较意义的事情
不能永远站在写几个类实现一些简单功能,维护别人的东西这个层次上,我也希望走的更远更高。程序规模较大,
对于管理复杂度的要求肯定越高。如果没有相应设计原则的遵循恐怕这个项目很容易夭折。勿以恶小而为之 勿以善小而不为。
那些破窗户理论,温水煮青蛙都说明了这些问题。
那么今天要初步学习就是如何设计可以工作的类。
1 提高类的内聚性
class Program{
//命令栈操作
public void InitializeCommandStack();
public void PushCommand();
public void PopCommand();
public void ShutdownCommandStack();
//格式化输出报表
public void InitializeReportFormat();
public void FormatReport();
public void PrintReport();
public void ShutdownReport();
//初始化全局资源
public void InitializeGlobalRes();
public Resorce getGlobalRes();
public void ShutDownGlobalDaRes();
……
}
看着样一个类实现三种功能:命令栈操作,报表操作,全局资源管理;但是你能发现这三者之间有什么联系呢?
唯一的联系就是被放到同一个类中,但实际上这三者之间没有练习,属于三个不同问题领域;内聚性非常的低,不满足高内聚设计原则。
由此抽象的类形成了不一致的接口抽象;
很惭愧我通常就是这么干的:写个通用的类,要什么接口,往里加函数,加成员数据就OK,而不管这些接口和数据之间有没有联系。
应该做的是将不同领域的问题单独提取出来抽象设计成一个类,实现类功能的单一原则。(功能单一,变化单一)
2 形成一致的抽象层次
class EmployeeCensus{
//Employee层次上
public void AddEmployee(Employee employee);
public void RmoveEmployee(Employee employee);
//Employee属性层次上
public void getEmployeeName(int index);
public void getEmployeeAddress(int index);
}
这个例子中层次是很明显看得出来,明显不合理。但是很惭愧:通常我是极少考虑这个层次问题。
在类内部或者子程序内部,管它什么层次,完成既定需求就可以了;
写着发现程序太长了,那就写一个函数将某一段封装起来,属性该如何很难决定;
3 基于接口的编程
class ScheduleUtil{
public void addAlarm();
public void delAlarm();
public void addReminder();
public void delReminder();
public void Initialize();
public void setParams();
public boolean checkValid();
public Widget getWidget();
public void NotifyHost();
}
class AlarmWidget(){
ScheduleUtil mScheduleUtil;
//mScheduleUtil.addAlarm();
}
class ReminderWidget(){
ScheduleUtil mScheduleUtil;
//mScheduleUtil.addReminder();
}
仅仅使用到此类中的几个相关方法,却要以以此类作为数据成员。似乎很不妥当的做法;
下面是进行统一接口的做法:
interface GeneralOperator{
public static final int OPERATOR_ADD_ALARM = 1;
public static final int OPERATOR_ADD_REMINDER = 2;
public static final int OPERATOR_CANCEL_ALARM = 3;
public static final int OPERATOR_CANCEL_REMINDER = 4;
public static final int OPERATOR_GET_TIME = 5;
public static final int OPERATOR_GET_WEEK = 6;
//提供一个接口统一处理相关的操作需求
public Object uniInteract(int operatorCmd);
}
class ScheduleUtil implements GeneralOperator{
@Override
public Object uniInteract(int operatorCmd) {
//执行命令参数相应操作
}
}
class AlarmWidget(){
GeneralOperator mScheduleUtil;
//mScheduleUtil.uniInteract(GeneralOperator.OPERATOR_ADD_ALARM);
}
class ReminderWidget(){
GeneralOperator mScheduleUtil;
//mScheduleUtil.uniInteract(GeneralOperator.OPERATOR_ADD_REMINDER);
}
软件设计的原则很多很有用,这里就是要先给自己提个醒,软件设计代码编写不能随意想当然而为之,
要站在一个较高的层面上分析设计!
以我目前的实践经验还不足以能对对这些原则加以能充分的理解和说明,学习中……
这些原则可参考:写的非常棒!
http://www.cnblogs.com/areliang/archive/2006/03/07/345111.html
http://coolshell.cn/articles/4535.html
代码大全里面核对表——类的质量:
抽象
类是否有一个中心目地
接口清晰简单明了
接口是否一致的抽象
……
封装
类的成员访问性降到最小
隐藏实现细节
封装对其他类依赖部分
避免考虑使用者如何使用类来设计类
……
继承:
is-a关系,派生类遵循LSP原则
……