标签: Oop
polymorphismmultiple-dispatchdouble-dispatch
…还是它们是同一件事?我注意到每一个都有自己的维基百科条目:,但我很难看到这些概念有什么不同
编辑:如何适应这一切?多重分派是一种多态性。在Java/C#/C++中,通过继承和重写存在多态性,但这不是基于两个或多个参数的多重分派(不仅仅是this,就像在Java/C#/C++中一样)多重分派更类似于函数重载(如Java/C++中所见),除非调用的函数取决于参数的运行时类型,而不是其静态类型。多重分派依赖于基于多态性的。典型的多态性在C++,C,VB.NET等中遇到。使用单一分派——即,被调用的函
标签: Oop
solid-principlessingle-responsibility-principletell-dont-ask
信息专家、告诉不要问和SRP通常一起被称为最佳实践。但我认为他们有分歧。这就是我要说的
有利于SRP但违反告知不要问&信息专家的代码:
Customer bob = ...;
// TransferObjectFactory has to use Customer's accessors to do its work,
// violates Tell Don't Ask
CustomerDTO dto = TransferObjectFactory.createFrom(bob);
有利
标签: Oop
fluent-interfaceleaky-abstraction
什么是流畅的界面?我找不到一个很好的定义,但我得到的只是一种我不太熟悉的语言(例如C++)中的长代码示例
还有,什么是泄漏抽象
感谢Eric Evans创造的流畅界面,这只是方法链接的另一个名称。马丁·福勒(Martin Fowler)就这一主题写了一篇文章,但大致如下:
m_Window = window::with()
.width(l_Width)
.height(l_Height)
.title("default window")
.left(200)
每次我遇到singleton模式的实现或任何静态类(即(几乎)只有静态成员的类)时,我都想知道这是否真的是一种黑客行为,因此严重滥用类和实例的原则,只是为了设计单个对象,而不是设计类和创建单个实例。在我看来,类的静态成员通常试图向类中添加一些他们实际上不应该拥有的特性,这些特性使它们自己成为对象
但这样实现单个对象真的很理想吗?
或者,您的看法完全不同,不认为这样的静态类或单例与实际对象有任何共同之处吗?假设我有一个具有单个配置文件的应用程序。如果我的语言不支持类外的全局函数(如Java或C#)
建模类时,首选的初始化方式是什么:
构造器,或
工厂方法
使用这两种方法的考虑因素是什么
在某些情况下,我更喜欢使用工厂方法,如果无法构造对象,该方法将返回null。这使得代码整洁。与从构造函数中抛出异常相比,我可以在采取其他操作之前简单地检查返回值是否不为null。(我个人不喜欢例外情况)
比如说,我在一个类上有一个构造函数,它需要一个id值。构造函数使用此值从数据库填充类。如果指定id的记录不存在,构造函数将抛出RecordNotFoundException。在这种情况下,我必须将所有此类类
因此,我正在编写一个应用程序,其中一个对象有一组委托对象,它将消息转发给这些对象。我的想法是我可以说
someObject sendMessage:aMessage
并且aMessage将被发送到someObject的所有委托(对于aMessage的任何值)。我能做到这一点的唯一方法是:
sendMessage:aMessage
| sel chunks kwords arglist msg |
chunks := aMessage findTokens:' '.
kwords := Arr
标签: Oop
virtualnew-operatormodifier
我知道,当我们在自己的基类中有一个虚拟函数,然后在派生类中重写它,并考虑在变量声明时进行转换,与在派生类中使用新的修饰符相比,我们得到不同的结果。但是为什么呢?这有什么逻辑上的原因吗?或者我们必须毫无理由地学习它?我想你指的是C
基本上,当子类方法与超类方法无关时,使用修饰符。它们共享名称,但不存在共享的多态行为。当您以多态方式重新定义名称时,这称为重写 我建议不要使用新的运算符,而是为该方法选择一个不同的名称。举一个例子,说明您所问的问题会使问题更清楚
为什么有人要将类标记为final或sealed?因为创建继承类型比大多数人想象的要困难得多。默认情况下,最好以这种方式标记所有类型,因为这将防止其他人从从未打算扩展的类型继承
是否应该扩展一个类型是由创建它的开发人员决定的,而不是后来出现并希望扩展它的开发人员。根据,“密封类主要用于防止派生。它们在编译时增加了另一个严格级别,提高了内存使用率,并触发了某些优化,从而提高了运行时效率。”
此外,来自:
版本控制:当一个类最初被密封时,它可以在将来更改为未密封,而不会破坏兼容性。(…)
性能:(
据我所知,如果在类层次结构中经常使用向下转换,那是没有好处的。
我同意这一点,但这条规则有哪些例外情况
这就是我的图形编辑器设计所显示的瘦:我有两个层次结构,其中几何图形层次结构与图形原语解耦。像这样:
public class GeometricPrimitive {...}
public class RectangeGeometric: Geometric Primitive {...}
public class GraphicPrimitive {...}
public class Re
这无疑是一个语言不可知的问题,也是困扰我很长一段时间的问题。举个例子也许能帮助我解释我所面临的困境:
假设我们有一个方法,负责读取一个文件,用一些对象(存储文件中的信息)填充一个集合,然后返回集合……如下所示:
public List<SomeObject> loadConfiguration(String filename);
公共列表加载配置(字符串文件名);
我们还要说,在实现此方法时,如果返回的集合为空(大小为0),则应用程序似乎无法继续。现在的问题是,这个验证(检查一个
我正在从头开始一个新项目,希望它干净/有良好的编码标准。这里经验丰富的开发人员喜欢按什么顺序在类中布局
答:1)公共方法2)私有方法3)公共变量4)私有变量
B:1)公共变量2)私有变量3)公共方法4)私有方法
C:1)公共变量2)公共方法3)私有方法4)私有变量
我通常喜欢将公共静态变量放在顶部,但是,公共静态方法是在构造函数之前列出的,还是应该始终首先列出构造函数?诸如此类的事情
我知道这是芬尼基,但我只是想知道:这方面的最佳实践是什么
PS:不,我不使用Cc。我知道。我是一个勒德分子。就我
我想知道,什么是好的做法:
private int value;
public int Value { get { return this.value; } }
private int DoSomething()
{
return this.Value + 1;
//OR
return this.value + 1;
}
所以,问题是如何处理类变量。您应该通过您的酒店访问它们还是直接访问它们?我选择直接访问。可以说,这都是“把它留在家里”的问题
标签: Oop
static-methodsstatic-variables
我有静态变量的概念,但是类中静态方法的好处是什么。我在一些项目上工作过,但我没有使方法成为静态的。每当我需要调用类的方法时,我都会创建该类的对象并调用所需的方法
Q:方法中的静态变量即使在执行方法时也保持其值,但只能在其包含方法中访问,但静态方法的最佳定义是什么
Q:调用静态方法而不创建该类的对象是静态方法的唯一好处吗
Q:静态方法的可访问范围是什么
感谢静态方法的一个常见用法是命名构造函数习惯用法。请参阅:。您对静态变量的描述更符合C中的描述。在面向对象术语中,静态变量的概念在概念上是不同的。
我有一个设计问题。
我有一个Drawer类,它调用了一系列画笔类的方法,我有一个预定义的形状,我想画它。每个形状都使用抽屉中的实例方法列表。我可以有多个笔刷对象
我想在运行时在抽屉实例中添加自定义形状,特别是新形状的方法列表
我已经为每个预定义的形状创建了一个类方法,它返回一个带有指令的BlockClosure。显然,我必须给每个BlockClosure指定笔刷对象作为参数。我想象一个集合,在抽屉类的每个实例中都有所有的blockclosure。
也许我可以继承SequenceableColle
我已经在自己的名称空间/库中编写了一个抽象基类TCPIP-sever。目前,我在解决方案的.exe项目中拥有派生类(更具体的TCPIP服务器;带有DataHandler)
我几乎100%肯定我会这样做,但我有一部分人想把派生类放在基类项目中。有什么好的理由支持/反对这一点?“为什么我需要基类库”
通常是因为您希望在多个项目中使用它
如果是这种情况,您是否需要在其他项目中使用派生类?为什么我需要基类库
通常是因为您希望在多个项目中使用它
如果是这种情况,您是否需要在其他项目中使用派生类?我支持这种
我有一个对象的代码。这个物体是你在石头剪纸游戏中可以做出的一个动作。
现在,该对象需要是一个整数(用于匹配协议)和一个字符串,以便于编写和查看
class Move:
def __init__(self, setMove):
self.numToName = {0:"rock", 1:"paper",2:"scissors"}
self.nameToNum = dict(reversed(pairing) for pairing in self.numT
所以我是一名java程序员,我知道重载函数意味着什么。此外,我用不同类型的参数重载了一个函数,并且可以用更少和更多的参数重载
我在一次采访中被问到这个问题。我真的不知道这是否有任何好处,也不知道面试官在这里得到了什么。它有性能优势吗?有什么想法吗
谢谢。这是关于通过允许使用默认值调用函数来提供灵活的接口。有些语言通过可选参数实现了这一点,但您可以通过重载或多或少地实现这一点 我以前用它来提供向后兼容性。采访者可能暗示依赖注入,这可以通过方法或构造函数来实现。肯定是为了向后兼容性。另外,如果很少使
我正在设计一个.Net库,它公开了所有只能标记为助手方法的方法。接收PersonID、RoleID等返回计算的工资、全年工资、奖金等
只设计一个具有GetSalary()、GetBonus()和GetHistoricSalary()等方法的静态类可以吗
或者我应该有一个接口ISalaryProcessor并在其中包含这些方法吗
对于选项2,实现类只有行为而没有数据,在尝试引入契约时,我是否创建了不需要的纯制造?如果您提供一个接口(或多个接口,根据),您的客户可以为库的部分提供自己的实现,并在
我试图弄清楚FuelPHP是如何编写的。。因为我不太懂OOP,所以当我上这门课时,我很困惑:
以下是我不了解的方法:
public static function _init()
{
static::$server_gmt_offset = \Config::get('server_gmt_offset', 0);
// some code here
}
public static function factory($timestamp = null, $timezone
这是一个如此简单和常见的场景,我想知道我是如何管理到现在,为什么我现在有问题
我有这个对象(基础结构组件的一部分)
这将在另一个程序集中创建,如下所示
var qi = new QueueItem(1,"myname",typeof(MyCommand),null);
这里没有什么不寻常的。但是,此对象将被发送到存储库,并保存到存储库中。队列对象将向存储库请求项目。存储库应重新创建QueueItem对象
但是,正如您所看到的,QueueItem属性是不变的,在创建项时,AddedOn属性只应
这里有一个理论性/学究式的问题:想象一下,房产中的每一个都可能被多个其他人拥有。此外,从所有权的一次迭代到下一次迭代,两个相邻的所有者可以决定部分合并所有权。例如:
territory 1, t=0: a,b,c,d
territory 2, t=0: e,f,g,h
territory 1, t=1: a,b,g,h
territory 2, t=1: g,h
也就是说,c和d不再拥有财产;可以说,g和h变成了肥猫
我目前将此数据结构表示为一棵树,其中每个孩子可以有多个家长。我的目标是将其
我有如下的类结构,下面的场景将创建一个循环引用。如何避免这种情况
public class classA
{
public classA()
{
classB b= new classB();
b.classBMethod();
}
public void classAMethod()
{
Console.WriteLine("Class A Method");
}
}
public class cl
我所学到的,并因此被限制的,是作为处理程序传递一个对象。我在Java和Objective-C编程项目中都使用过这种方法,而且它是有效的
然而,我偶然发现了一个将类注册为处理程序而不是对象的框架。我希望该框架是开源的,这样我就可以看到它是如何工作的,但它不是:/
当心!注册类之后,我实现了非静态方法来处理事件。如果它们是静态的,很明显这是如何工作的,我真的很讨厌这种方法
因此,以下是我的问题:
类处理程序如何工作以及与普通对象处理程序的区别
你什么时候会推荐一款而不是另一款
这个图案有名字吗
我有三张桌子:
发布
类别
后分类(多对多关系表)
当用户为帖子选择一个或多个类别时,它可以正常工作。但有一种情况是,当用户没有选择任何类别时,我应该如何管理这些未分类的帖子
我想了两种方法,我不知道哪种更好
1。不应将未分类的邮件插入[邮政分类]。
问题:
a) 在URL路径中,我使用“/Post/Category/Travel”来显示分类文章。现在用户想要列出所有未分类的帖子,我只能使用类似“/Post/Category/Uncategorized”的内容。这将导致许多代码更改,以便将“未分
在工作(银行)中,我们正在重新设计我们的MW/Web服务。我们正在使用自下而上的方法来构建这些服务。我们正在使用Java、jax和ws。所以我需要创建要遵循的规则。到目前为止,我有两个问题:
我们应该为我们的对象字段创建类型,例如在类客户机中,我们应该创建一个手机对象还是使用简单的字符串。我可以看到优点和缺点,物体会变得很重,但很容易验证和控制
还有其他想法吗
我们应该使用SOAP内置错误还是创建自己的错误状态代码(可能在SOAP头中)。我非常喜欢SOAP错误,因为它直接映射到Java异常
提前
我在MATLAB中有一个对象数组,我在循环中调用了它们的构造函数:
antsNumber = 5;
for counter = 1: antsNumber
ant(counter) = TAnt(source, target);
end
MATLAB警告我使用预分配来加快进程。我确实知道预分配的好处,但我不知道如何对对象进行预分配。以下链接可能会有所帮助:
http://www.mathworks.com/help/techdoc/matlab_oop/brd4btr.html#br
我只是通过构建一个虚拟的图书馆管理系统项目来实践JavaOOPS的概念
最初我有Book、Customer、Administrator类(Customer、Administrator扩展了抽象用户类)
然后,我创建了列表类BookCollection,CustomerCollection,它在ArrayList中保存上述类的实例列表(暂时不处理数据库),并在相应的ArrayList上执行添加、删除和排序方法(只有一个内联问题:一旦我开始处理数据库,用数据库操作替换与ArrayList相关的代码,
这是一个设计问题,我也在努力寻找答案。我正在设计一个基于对象的系统,我需要识别并详细说明运行使用这些对象的业务所需的所有数据。我正在努力解决的问题是,这个对象的一部分属性和一部分元数据是什么,有什么区别,我为什么要在意
我认为所有权必须存在,才能使其存在。而元数据是为了业务流程的目的而描述该对象的数据
作为一个例子,我会说这个物体是一辆汽车,我的业务是销售汽车。汽车的性能将是品牌、颜色、发动机尺寸。然而,一段元数据可能是IsSold或ForSale,其中元数据与销售汽车的业务流程相关
价格似乎是
背景:
我已经在我的live服务器上安装了PHP Memcached扩展。
尽管做出了各种努力,但我似乎无法在XAMPP开发箱中安装Memcached,因此我仅依靠以下代码在Live server上实例化Memcached:
我的连接文件,包含在每个页面中:
// MySQL connection here
// Memcached
if($_SERVER['HTTP_HOST'] != 'test.mytestserver') {
$memcache = new Memcached(
我需要在不同的实体之间映射,以便在两个系统之间创建同步工具。映射是1:1,我将在4-5个不同的实体之间映射
例如
通信是通过RESTAPI在JSON中进行的,对于不同的请求,我必须将对象转换为JSON表示形式
我希望了解您在以下决定中的想法:
1) 在每个类中,创建一个类方法,该方法知道如何转换为其他系统中相应的对象。每个类都知道如何通过实现toJSON和toXML方法来表示自己
例如
2) 直接使用转换器类(Object->JSON)和方法将对象转换为另一个系统中相应的JSON。例如。
Con
当我读到关于继承的文章时,我总是对某个例子感到困惑
通常有一个与下面的例子类似的例子
class Shape
{
public:
Shape() {}
virtual ~Shape () {}
virtual void Draw() = 0;
};
class Cube : public Shape
{
public:
Cube(){}
~Cube(){}
virtual void Draw();
};
Shape* newCube = new C
我对课程或OOP不是很有经验,
我对我得到的一些结果感到困惑
我正在尝试对我创建的类使用type()
class TestClass:
pass
my_class = TestClass()
print type(my_class)
上面的代码返回
<type: 'instance'>
根据我的理解,my_class应该初始化为TestClass对象。。正确的?为什么输出不是TestClass。另外,如果可能的话,我需要修改什
我正在尝试初始化一个基本的堆栈,包括push和pop函数。
测试时出现问题。在代码中,您会注意到我已经推了2次,因此堆栈的打印应该显示[5,5],而它显示的是无。我可以修改代码使其最终工作,但这样我就不能完全理解底层的概念和我的方法的错误。所以我寻求建议和指点。
请检查这些代码并告诉我我做错了什么
这是包含类及其所有函数的代码,名为stack\u class:
class Stack:
def __init__(self):
self._values = []
让我们假设我们有两类:患者和药物胺化。我们希望为特定患者进行所有检查。哪一个更好:
patient.getexamions()
检查获取(患者)
您将如何实施第二种方法?这将迫使你循环检查所有检查,看看哪一项是关于你的患者的
然而,第一种方法将允许每个患者进行自己的检查,从而立即恢复检查。因此,我倾向于这种方法
为对象提供尽可能多的信息(不降低安全性问题),使其能够独立运行。医生通常为每个患者都有一个文件,在每个患者的文件中,都有一个医疗检查列表
所以,你从医生办公室得到病人,然后从病人的档案中
假设我有一个简单的Java类,它存储一个时间戳:
public final class Timestamp {
private final long value;
public Timestamp(final long value) {
this.value = value;
}
public long getValue() {
return value;
}
}
这是不变的。但是如果我编写了一个名为getProgress()的方法,而不是getValu
标签: Oop
solid-principlesliskov-substitution
比如说,我有A类方法M:
private void M()
{
Do1();
Do2();
}
B类扩展了A类
问题:从B的实例调用时,我需要不执行Do2()
我有一些想法,但不确定哪些不会违反OOP和可靠的规则
使Do2虚拟。
这个解决方案在我看来很奇怪,因为我重写了一个“什么都不做”的方法,而重写是为了“做某事而不是做某事”或“做某事之外的事情”
创建boolprotectedflag属性
这个解决方案也不完美,但我可以控制执行流,并可以决定是否调用Do2
传递构造函数标志
标签: Oop
plcstructured-text
我正在使用结构化文本为施耐德PLC编写一个程序,并尝试使用面向对象编程
作为PLC编程的新手,我编写了一个简单的测试程序,如下所示:
okFlag:=myObject.aMethod();
IF okFlag THEN
// it's ok, go on
ELSE
// error handling
END_IF
aMethod必须执行一些操作,等待结果(有一个“超时”检查以避免死锁),然后返回TRUE或FALSE
这是我在程序执行期间所期望的
1) 当okFlag:=my
我有几个带有字段的数据类,这些字段在表单中使用,如果任何字段已填充,则需要它们具有返回true的方法
我不想为所有的类重写这个,所以我现在就这样做:
data class Order(var consumer: String, var pdfs: List<URI>): Form {
override val isEmpty(): Boolean
get() = checkEmpty(consumer, pdfs)
}
data class Somet
我正在学习OOP,我想知道抽象和封装。
说抽象就是选择要显示的信息,而封装就是实现它的方式,这样说对吗?如果我在采访中这样说,这是一种正确的解释方式吗
抽象和封装是互补的概念:抽象关注对象的可观察行为。。。封装主要关注导致这种行为的实现。。。封装通常是通过信息隐藏来实现的,信息隐藏是隐藏对象的所有秘密的过程,这些秘密与对象的基本特征无关
这是我能找到的最简单的答案。资料来源:
基于这一点以及我对OOP的了解,我想在采访中说,这将是一个非常基本但可以接受的答案。关于那个帖子有很多好的信息。享受吧
标签: Oop
solid-principlessingle-responsibility-principle
在电子邮件发送的上下文中,是否可以查询方法内部的外部信息,或者是否应该像第二个示例那样传递值
一,
二,
是,从该方法进行查询仍然是单一责任(该方法仍然只做一件事:发送电子邮件)。这本身并不违背原则
但是,方法应该直接传递公司名称,而getCompanyName方法不应该属于同一类型
如果你想遵循SRP,你实际上也必须在类型上这样做:类真的应该负责从(大概)数据库发送和获取数据吗
向公司名称发送邮件
从公司id查找公司名称
这是两份各自应得的工作
void sendEmail(int com
我有一些数据,我正试图筛选,但我想不出一个聪明的方法来做这件事。假设我有3种类型:
A、 它们都扩展了一个类S
如果我创建一个工厂,只创建并返回类型为S的对象,它看起来会非常程序化。工厂的伪代码实现如下:
class Factory {
func create_obj(input_data) -> S {
if type(input_data) is A {
return A()
}
else if type(
我有一个类TestClass:
classdef TestClass < handle
methods
function o = doNothing(vec)
o = vec;
end
end
end
执行此代码后,我希望x包含[1,0,1],但由于某种原因doNothing返回TestClass对象
我对Octave/Matlab非常陌生,所以我的问题可能是基本误解的结果,但我无法找到答案。任何帮助都将不胜感激。对象方法的第一个输入是其自身的一个实例
我有一个问题要在没有抽象方法的抽象类和有接口的基类之间进行选择
我有两个想法:
1.
假设我有一个AbstractRenderer:
abstract class AbstractRenderer
{
protected $shape;
public function __construct(AbstractShape $shape)
{
$this->shape = $shape;
}
public function rend
当您使用getter和setter定义变量/属性,使语言不会自动生成支持变量时,它叫什么
例如,在Swift中,我们可以定义一个不创建支持变量的modalViewController属性:
extension MyViewController {
var modalViewController: UIViewController? {
get { return self.presentedViewController }
set { self.presen
我正在构建一个有敌人和玩家的游戏,所有这些都被设置为具有不同的动画和行为状态。两者的父类都是Entity.lua,它们从中继承变量和方法。然而,当敌人和玩家都继承变量时,出于某种原因,敌人不会继承方法。例如,如果我尝试调用snakey:changeState('search'),它会给我一条错误消息“尝试调用方法'changeState'(一个nil值)”
在过去的几场游戏中,我使用相同的顺序创建实体,但从未遇到过这个问题。事实上,如果我以与敌人相同的方式创建玩家,文件和位置,我不会收到任何错误
这是一个更具理论性的问题
例如,在Squeak/Smalltalk中,可以在运行时添加方法,因此可以说该类没有定义协议——因为协议所代表的“契约”可能在运行时发生变化,因此它实际上并不适用
然而,我要问的是一种通用的动态语言。在所有动态语言中,类在运行时是否可以这样扩展?如果不是,那么说即使语言是动态的,类仍然有一个协议是正确的吗
标签: Oop
mixinsrakucompositionrakudo
如果我的角色定义为:
role R { method answer { 42 } }
这两条线之间有什么区别(如果有):
my $a = 'question' does R;
my $b = 'question' but R;
它们看起来非常相似:
say $a.answer; # OUTPUT: «42»
say $b.answer; # OUTPUT: «42»
say $a.WHAT; # OUTPUT: «(Str+{R})»
say $b.WHAT; # OU
标签: Oop
Uml
aggregationclass-diagram
我试图解决这个问题:
为汽车租赁公司绘制面向对象模型的UML类图,该模型跟踪汽车、租车人和租车人。创建一个UML类图来表示这些信息。显示正确的类和关系就足够了。不要向类添加属性或方法
我在想,租车人和汽车公司应该是联合体,汽车公司和租车人应该是联合体。但是,建议的解决方案(此处简化)与我的预期不符:
该解决方案将所有关系显示为聚合。有人能帮我理解为什么它们都是聚合,而不是我所认为的关联和组合吗?您自己的评论
我在想,租车者和汽车公司应该是联合体
是的,这是有道理的:一个租车人可能是一家汽车公司
这里有一个UML图,让事情更清楚。
如您所见,StateManager和State都相互引用。
我怎样才能避免意大利面代码?我应该让StateManager成为一个单例类吗?当我们这样做的时候,游戏课应该是一个单人课吗?我可以很容易地做到这一点,但我真的不喜欢游戏中的其他类能够访问游戏类或statemanager类,即使我是唯一的程序员。双向引用没有错。查看QWidgets的Qt父/子模型。如果每个状态只能影响一个StateManager,请使每个状态在其构造中采用指向StateManager
我试图想象一个具有多个行为的用例参与者如何在应用程序中实际出现
以以下现实世界中过于简单的情况为例:
环境咨询组织有一名项目经理,负责:创建和管理客户;项目;设施和建筑物、设备和用品。很多只是积垢,但还有很多
拥有一个包含所有隐含行为的ProjectManager类有意义吗?只要看一下用例图,我就可以看到需要20多种方法
与其把所有的鸡蛋放在一个篮子里,不如将责任分成不同的角色,然后将这些角色分配给PM
我的意思是,请容忍我,想象一下:
接口:CustomerRelations
职责:与客户相关
1 2 3 4 5 6 ...
下一页 最后一页 共 121 页